小说绘上架版本

This commit is contained in:
xtfei2011
2021-02-07 11:24:08 +08:00
commit ee5c1c8b12
1762 changed files with 115892 additions and 0 deletions
@@ -0,0 +1,58 @@
//
// WXYZ_AudioSettingHelper.h
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioSettingHelper : NSObject
interface_singleton
// 倒计时
- (NSInteger)getReadTiming;
- (void)setReadTimingWithIndex:(NSInteger)readTimingIndex;
- (NSArray *)getReadTimingKeys;
- (NSArray *)getReadTimingValues;
// 开始倒计时
- (void)startTimingFinishBlock:(void(^)(void))finishBlock;
- (void)getCurrentTimingBlock:(void(^)(NSUInteger currentTime))currentTimeBlock finishBlock:(void(^)(void))finishBlock;
// 声音
- (NSString *)getReadVoiceTitleWithProducitionType:(TFProductionType)productionType;
- (NSInteger)getReadVoiceWithProducitionType:(TFProductionType)productionType;
- (void)setReadVoiceWithIndex:(NSInteger)readVoiceIndex producitionType:(TFProductionType)productionType;
- (NSArray *)getReadVoiceKeysWithProducitionType:(TFProductionType)productionType;
- (NSArray *)getReadVoiceValuesWithProducitionType:(TFProductionType)productionType;
// 语速
- (NSInteger)getReadSpeedWithProducitionType:(TFProductionType)productionType;
- (void)setReadSpeedWithIndex:(NSInteger)readSpeedIndex producitionType:(TFProductionType)productionType;
- (NSArray *)getReadSpeedKeysWithProducitionType:(TFProductionType)productionType;
- (NSArray *)getReadSpeedValuesWithProducitionType:(TFProductionType)productionType;
- (void)playPageViewShow:(BOOL)show productionType:(TFProductionType)productionType;
- (BOOL)isPlayPageShowingWithProductionType:(TFProductionType)productionType;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,206 @@
//
// WXYZ_AudioSettingHelper.m
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioSettingHelper.h"
#import "WXYZ_Player.h"
#import "WXYZ_GCDTimer.h"
#import <MediaPlayer/MediaPlayer.h>
@interface WXYZ_AudioSettingHelper ()
@property (nonatomic, strong) WXYZ_GCDTimer *countdownTimer;
@property (nonatomic, assign) NSInteger read_timing; // 听书倒计时(有声和ai的计时同步)
@end
@implementation WXYZ_AudioSettingHelper
implementation_singleton(WXYZ_AudioSettingHelper)
// 倒计时
- (NSInteger)getReadTiming
{
return self.read_timing;
}
- (void)setReadTimingWithIndex:(NSInteger)readTimingIndex
{
_read_timing = readTimingIndex;
}
- (NSArray *)getReadTimingKeys
{
return @[TFLocalizedString(@"不开启"), TFLocalizedString(@"听完本章节"), TFLocalizedString(@"15分钟"), TFLocalizedString(@"30分钟"), TFLocalizedString(@"60分钟"), TFLocalizedString(@"90分钟")];
}
- (NSArray *)getReadTimingValues
{
return @[@"0", @"1", @"900", @"1800", @"3600", @"5400"];
}
// 声音
- (NSString *)getReadVoiceTitleWithProducitionType:(TFProductionType)productionType
{
return [[self getReadVoiceKeysWithProducitionType:productionType] objectAtIndex:[self getReadVoiceWithProducitionType:productionType]];
}
- (NSInteger)getReadVoiceWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
return 0;
} else {
NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey:@"xtfei_ai_read_voice"];
return string?[string integerValue] : 0;
}
}
- (void)setReadVoiceWithIndex:(NSInteger)readVoiceIndex producitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
} else {
[[NSUserDefaults standardUserDefaults] setObject:[TFUtilsHelper formatStringWithInteger:readVoiceIndex] forKey:@"xtfei_ai_read_voice"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
- (NSArray *)getReadVoiceKeysWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
return @[];
} else {
return @[TFLocalizedString(@"情感女声"), TFLocalizedString(@"标准女声"), TFLocalizedString(@"标准男声")];
}
}
- (NSArray *)getReadVoiceValuesWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
return @[];
} else {
return @[@"xiaoyan", @"vixq", @"aisbabyxu"];
}
}
// 语速
- (NSInteger)getReadSpeedWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey:@"xtfei_audio_read_speed"];
return string?[string integerValue]:2;
} else {
NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey:@"xtfei_ai_read_speed"];
return string?[string integerValue]:2;
}
}
- (void)setReadSpeedWithIndex:(NSInteger)readSpeedIndex producitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
[[NSUserDefaults standardUserDefaults] setObject:[TFUtilsHelper formatStringWithInteger:readSpeedIndex] forKey:@"xtfei_audio_read_speed"];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
[[NSUserDefaults standardUserDefaults] setObject:[TFUtilsHelper formatStringWithInteger:readSpeedIndex] forKey:@"xtfei_ai_read_speed"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
- (NSArray *)getReadSpeedKeysWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
return @[TFLocalizedString(@"0.5倍"), TFLocalizedString(@"0.75倍"), TFLocalizedString(@"1倍"), TFLocalizedString(@"1.25倍"), TFLocalizedString(@"1.5倍")];
} else {
return @[TFLocalizedString(@"0.5倍"), TFLocalizedString(@"0.75倍"), TFLocalizedString(@"1倍"), TFLocalizedString(@"1.25倍"), TFLocalizedString(@"1.5倍")];
}
}
- (NSArray *)getReadSpeedValuesWithProducitionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAudio) {
return @[@"0.5", @"0.80", @"1.0", @"1.25", @"1.5"];
} else {
return @[@"0.5", @"0.80", @"1.0", @"1.25", @"1.5"];
}
}
- (void)startTimingFinishBlock:(void(^)(void))finishBlock
{
CGFloat duration = [[[self getReadTimingValues] objectAtIndex:self.read_timing] floatValue];
if (self.read_timing == 0 || self.read_timing == 1) {
[self.countdownTimer stopTimer];
if (finishBlock) {
finishBlock();
}
return;
}
[self.countdownTimer stopTimer];
[self.countdownTimer startTimerWithTimeDuration:duration];
}
- (void)getCurrentTimingBlock:(void(^)(NSUInteger currentTime))currentTimeBlock finishBlock:(void(^)(void))finishBlock
{
// if ((self.read_timing == 0 || self.read_timing == 1) && ) {
// if (finishBlock) {
// finishBlock();
// }
// }
self.countdownTimer.timerRunningBlock = ^(NSUInteger runTimes, CGFloat currentTime) {
if (currentTimeBlock) {
currentTimeBlock([[NSNumber numberWithFloat:currentTime] integerValue]);
}
};
WS(weakSelf)
self.countdownTimer.timerFinishedBlock = ^{
weakSelf.read_timing = 0;
if (finishBlock) {
finishBlock();
}
};
}
- (WXYZ_GCDTimer *)countdownTimer
{
if (!_countdownTimer) {
_countdownTimer = [[WXYZ_GCDTimer alloc] initCountdownTimerWithTimeDuration:10 immediatelyCallBack:YES];
}
return _countdownTimer;
}
static BOOL aiPlayPageShow = NO;
static BOOL audioPlayPageShow = NO;
- (void)playPageViewShow:(BOOL)show productionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAi) {
aiPlayPageShow = show;
}
if (productionType == TFProductionTypeAudio) {
audioPlayPageShow = show;
}
}
- (BOOL)isPlayPageShowingWithProductionType:(TFProductionType)productionType
{
if (productionType == TFProductionTypeAi) {
return aiPlayPageShow;
}
if (productionType == TFProductionTypeAudio) {
return audioPlayPageShow;
}
return NO;
}
@end
@@ -0,0 +1,25 @@
//
// WXYZ_AudioDownloadTableViewCell.h
// WXReader
//
// Created by Andrew on 2020/3/20.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "TFBasicTableViewCell.h"
#import "WXYZ_DownloadManagerEnumProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioDownloadTableViewCell : TFBasicTableViewCell
@property (nonatomic, strong) TFProductionChapterModel *chapterModel;
// 是否是缓存状态
@property (nonatomic, assign) BOOL isCacheState;
@property (nonatomic, assign) WXYZ_ProductionDownloadState cellDownloadState;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,146 @@
//
// WXYZ_AudioDownloadTableViewCell.m
// WXReader
//
// Created by Andrew on 2020/3/20.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadTableViewCell.h"
#import "WXYZ_AudioDownloadManager.h"
@implementation WXYZ_AudioDownloadTableViewCell
{
UIImageView *selectImageView;
UILabel *audioChapterLabel;
UIImageView *fileIcon;
UILabel *fileLabel;
}
- (void)createSubviews
{
[super createSubviews];
selectImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"audio_download_unselect"]];
[self.contentView addSubview:selectImageView];
[selectImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kMargin);
make.centerY.mas_equalTo(self.contentView.mas_centerY);
make.width.height.mas_equalTo(20);
}];
audioChapterLabel = [[UILabel alloc] init];
audioChapterLabel.textAlignment = NSTextAlignmentLeft;
audioChapterLabel.textColor = kBlackColor;
audioChapterLabel.font = kMainFont;
audioChapterLabel.numberOfLines = 2;
[self.contentView addSubview:audioChapterLabel];
[audioChapterLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(selectImageView.mas_right).with.offset(kMargin);
make.top.mas_equalTo(self.contentView.mas_top).with.offset(kHalfMargin);
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
make.height.mas_equalTo(15);
}];
fileIcon = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"audio_file_icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
fileIcon.userInteractionEnabled = YES;
fileIcon.tintColor = kGrayTextColor;
[self.contentView addSubview:fileIcon];
[fileIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(audioChapterLabel.mas_left);
make.top.mas_equalTo(audioChapterLabel.mas_bottom).with.offset(kQuarterMargin);
make.width.mas_equalTo(15);
make.height.mas_equalTo(15);
}];
fileLabel = [[UILabel alloc] init];
fileLabel.textColor = kGrayTextColor;
fileLabel.textAlignment = NSTextAlignmentLeft;
fileLabel.font = kFont10;
[self.contentView addSubview:fileLabel];
[fileLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(fileIcon.mas_right).with.offset(kQuarterMargin);
make.centerY.mas_equalTo(fileIcon.mas_centerY);
make.right.mas_equalTo(self.contentView.mas_right).with.offset(-kMargin);
make.height.mas_equalTo(fileIcon.mas_height);
make.bottom.mas_equalTo(self.contentView.mas_bottom).with.offset(-kHalfMargin).priorityLow();
}];
}
- (void)setChapterModel:(TFProductionChapterModel *)chapterModel
{
_chapterModel = chapterModel;
fileLabel.text = [TFUtilsHelper convertFileSize:chapterModel.size];
NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:chapterModel.chapter_title ? : @""];
if (chapterModel.is_preview == 1 && [[WXYZ_AudioDownloadManager sharedManager] getChapterDownloadStateWithProduction_id:chapterModel.production_id chapter_id:chapterModel.chapter_id] != WXYZ_ProductionDownloadStateDownloaded) {
NSTextAttachment *attch = [[NSTextAttachment alloc] init];
attch.image = [UIImage imageNamed:TFLocalizedString(@"audio_directory_pay")];
attch.bounds = CGRectMake(0, 0, kGeometricWidth(10, 246, 90), 10);
NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attch];
[attri insertAttributedString:string atIndex:0];
}
audioChapterLabel.attributedText = attri;
}
- (void)setCellDownloadState:(WXYZ_ProductionDownloadState)cellDownloadState
{
if (_cellDownloadState != cellDownloadState) {
_cellDownloadState = cellDownloadState;
switch (cellDownloadState) {
case WXYZ_ProductionDownloadStateNormal:
{
selectImageView.image = [UIImage imageNamed:@"audio_download_unselect"];
audioChapterLabel.textColor = kBlackColor;
self.backgroundColor = kWhiteColor;
}
break;
case WXYZ_ProductionDownloadStateDownloading:
{
selectImageView.image = [UIImage imageNamed:@"audio_downloading_list"];
audioChapterLabel.textColor = kBlackColor;
self.backgroundColor = kWhiteColor;
}
break;
case WXYZ_ProductionDownloadStateDownloaded:
{
if (self.isCacheState) {
selectImageView.image = [UIImage imageNamed:@"audio_download_unselect"];
audioChapterLabel.textColor = kBlackColor;
self.backgroundColor = kWhiteColor;
} else {
selectImageView.image = [UIImage imageNamed:@"audio_download_unenable"];
audioChapterLabel.textColor = kGrayTextColor;
self.backgroundColor = kGrayViewColor;
}
}
break;
case WXYZ_ProductionDownloadStateSelected:
{
selectImageView.image = [UIImage imageNamed:@"audio_download_select"];
audioChapterLabel.textColor = kBlackColor;
self.backgroundColor = kWhiteColor;
}
break;
case WXYZ_ProductionDownloadStateFail:
selectImageView.image = [UIImage imageNamed:@"audio_download_fail_list"];
audioChapterLabel.textColor = kBlackColor;
self.backgroundColor = kWhiteColor;
break;
default:
break;
}
}
}
@end
@@ -0,0 +1,20 @@
//
// WXYZ_AudioDownloadViewController.h
// WXReader
//
// Created by Andrew on 2020/3/20.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "TFDownloadViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioDownloadViewController : TFDownloadViewController
// 预防作品model为空的情况
@property (nonatomic, assign) NSInteger production_id;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,517 @@
//
// WXYZ_AudioDownloadViewController.m
// WXReader
//
// Created by Andrew on 2020/3/20.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadViewController.h"
#import "WXYZ_AudioDownloadTableViewCell.h"
#import "WXYZ_AudioPlayPageMenuView.h"
#import "WXYZ_AudioDownloadManager.h"
#import "TFReadRecordManager.h"
#import "WXYZ_ChapterBottomPayBar.h"
@interface WXYZ_AudioDownloadViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) TFProductionModel *audioModel;
@property (nonatomic, assign) CGFloat totalMemorySize;
@property (nonatomic, assign) BOOL payBarShowing;
@property (nonatomic, strong) UIButton *downloadButton;
@property (nonatomic, strong) UIActivityIndicatorView *downloadIndicatorView;
@property (nonatomic, strong) WXYZ_AudioDownloadManager *audioDownloadManager;
@property (nonatomic, weak) UILabel *headerTitleLabel;
@end
@implementation WXYZ_AudioDownloadViewController
{
UILabel *memoryBarView;
TFButton *selectAllButton;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initialize];
[self createSubviews];
[self initDownloadManager];
[self netRequest];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setStatusBarDefaultStyle];
}
- (void)initialize
{
[self setNavigationBarTitle:TFLocalizedString(@"批量下载")];
self.totalMemorySize = 0;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(netRequest) name:Notification_Login_Success object:nil];
}
- (void)createSubviews
{
self.mainTableView.delegate = self;
self.mainTableView.dataSource = self;
[self.view addSubview:self.mainTableView];
[self.mainTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(PUB_NAVBAR_HEIGHT);
make.width.mas_equalTo(self.view.mas_width);
make.height.mas_equalTo(self.view.mas_height).with.offset(- PUB_NAVBAR_HEIGHT - PUB_TABBAR_HEIGHT - 20);
}];
memoryBarView = [[UILabel alloc] init];
memoryBarView.numberOfLines = 2;
memoryBarView.backgroundColor = kColorRGB(251, 251, 251);
memoryBarView.font = kFont10;
memoryBarView.textAlignment = NSTextAlignmentCenter;
memoryBarView.textColor = kGrayTextColor;
memoryBarView.text =[NSString stringWithFormat:@"%@%@", TFLocalizedString(@"可用空间"), [TFUtilsHelper getRemainingMemorySpace]];
[self.view addSubview:memoryBarView];
[memoryBarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(self.mainTableView.mas_bottom);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(20);
}];
selectAllButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"全选") buttonImageName:@"audio_download_unselect" buttonIndicator:TFButtonIndicatorImageLeftBothLeft];
selectAllButton.buttonTitleColor = kBlackColor;
selectAllButton.buttonTitleFont = kMainFont;
selectAllButton.graphicDistance = 10;
selectAllButton.buttonImageScale = 0.4;
selectAllButton.hidden = YES;
selectAllButton.tag = 0;
selectAllButton.backgroundColor = [UIColor whiteColor];
[selectAllButton addTarget:self action:@selector(checkallClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:selectAllButton];
[selectAllButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMargin);
make.top.equalTo(memoryBarView.mas_bottom);
make.height.mas_equalTo(PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET);
}];
self.downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.downloadButton.backgroundColor = kGrayTextLightColor;
self.downloadButton.enabled = NO;
[self.downloadButton setTitle:TFLocalizedString(@"立即下载") forState:UIControlStateNormal];
[self.downloadButton setTitleColor:kWhiteColor forState:UIControlStateNormal];
[self.downloadButton.titleLabel setFont:kMainFont];
[self.downloadButton addTarget:self action:@selector(downloadClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.downloadButton];
[self.downloadButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.view.mas_right);
make.top.mas_equalTo(selectAllButton.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH / 3);
make.height.mas_equalTo(selectAllButton.mas_height);
}];
[selectAllButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.downloadButton.mas_left).offset(-kHalfMargin);
}];
self.downloadIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
self.downloadIndicatorView.hidesWhenStopped = YES;
[self.downloadButton addSubview:self.downloadIndicatorView];
[self.downloadIndicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.downloadButton.mas_centerX);
make.centerY.mas_equalTo(self.downloadButton.mas_centerY);
make.width.height.mas_equalTo(self.downloadButton.mas_height);
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataSourceArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TFProductionChapterModel *chapterModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
static NSString *cellName = @"WXYZ_AudioDownloadTableViewCell";
WXYZ_AudioDownloadTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_AudioDownloadTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.chapterModel = chapterModel;
cell.cellDownloadState = [[self.selectSourceDictionary objectForKey:[TFUtilsHelper formatStringWithInteger:chapterModel.chapter_id]] integerValue];
cell.hiddenEndLine = self.dataSourceArray.count - 1 == indexPath.row;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
//section头间距
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30;
}
//section头视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 30)];
view.backgroundColor = [UIColor clearColor];
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 30)];
mainView.backgroundColor = kColorRGB(251, 251, 251);
[view addSubview:mainView];
UILabel *headerTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(kMargin, 0, SCREEN_WIDTH / 2, 30)];
self.headerTitleLabel = headerTitleLabel;
headerTitleLabel.backgroundColor = [UIColor clearColor];
headerTitleLabel.font = kFont12;
// headerTitleLabel.text = [NSString stringWithFormat:@"%@ %zd %@", TFLocalizedString(@"已下载"), [[WXYZ_AudioDownloadManager sharedManager] getDownloadChapterCountWithProduction_id:self.audioModel.production_id], TFLocalizedString(@"章")];
headerTitleLabel.text = [NSString stringWithFormat:@"%@ %zd %@", TFLocalizedString(@""), self.dataSourceArray.count, TFLocalizedString(@"")];
headerTitleLabel.textColor = kGrayTextColor;
[mainView addSubview:headerTitleLabel];
CGFloat width = [TFViewHelper getDynamicWidthWithLabelFont:kFont12 labelHeight:30.0 labelText:TFLocalizedString(@"选章标题") maxWidth:240.0];
width += kMargin;
TFButton *selectionButton = [[TFButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH - width - kHalfMargin, 0, width, 30) buttonTitle:TFLocalizedString(@"选章标题") buttonImageName:@"audio_selection" buttonIndicator:TFButtonIndicatorTitleRight];
selectionButton.tag = 0;
selectionButton.buttonTintColor = kGrayTextColor;
selectionButton.buttonTitleFont = kFont12;
selectionButton.graphicDistance = 2;
selectionButton.buttonImageScale = 0.4;
[selectionButton addTarget:self action:@selector(selectionButtonClick) forControlEvents:UIControlEventTouchUpInside];
[mainView addSubview:selectionButton];
return view;
}
//section底部间距
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return CGFLOAT_MIN;
}
//section底部视图
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, CGFLOAT_MIN)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TFProductionChapterModel *chapterModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
WXYZ_AudioDownloadTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch (cell.cellDownloadState) {
case WXYZ_ProductionDownloadStateNormal:
case WXYZ_ProductionDownloadStateFail:
[self setCollectionCellDownloadStateWithChapter_id:chapterModel.chapter_id downloadState:WXYZ_ProductionDownloadStateSelected];
[self reloadToolBar];
break;
case WXYZ_ProductionDownloadStateSelected:
[self setCollectionCellDownloadStateWithChapter_id:chapterModel.chapter_id downloadState:WXYZ_ProductionDownloadStateNormal];
[self reloadToolBar];
break;
default:
break;
}
}
- (void)checkallClick:(TFButton *)sender
{
self.totalMemorySize = 0;
for (TFProductionChapterModel *chapterModel in self.dataSourceArray) {
if ([[WXYZ_AudioDownloadManager sharedManager] getChapterDownloadStateWithProduction_id:chapterModel.production_id chapter_id:chapterModel.chapter_id] == WXYZ_ProductionDownloadStateNormal) {
self.totalMemorySize = self.totalMemorySize + chapterModel.size;
}
}
for (NSString *t_chapter_id in self.selectSourceDictionary.allKeys) {
if (!sender.selected) { // 全选状态
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateNormal || [[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateFail) {
[self setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateSelected];
}
} else {
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateSelected) {
[self setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateNormal];
}
}
}
sender.selected = !sender.selected;
[self reloadToolBar];
}
- (void)selectionButtonClick
{
WS(weakSelf)
WXYZ_AudioPlayPageMenuView *chooseMenuView = [[WXYZ_AudioPlayPageMenuView alloc] init];
chooseMenuView.menuListArray = self.dataSourceArray;
chooseMenuView.totalChapter = self.audioModel.total_chapters;
chooseMenuView.chooseMenuBlock = ^(WXYZ_MenuType menuType, NSInteger chooseIndex) {
/* 滚动指定段的指定row 到 指定位置*/
[weakSelf.mainTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:chooseIndex * 30 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
};
[chooseMenuView showWithMenuType:WXYZ_MenuTypeAudioSelection];
}
- (void)initDownloadManager
{
WS(weakSelf)
self.audioDownloadManager = [WXYZ_AudioDownloadManager sharedManager];
self.audioDownloadManager.downloadChapterStateChangeBlock = ^(WXYZ_DownloadChapterState state, NSInteger production_id, NSInteger chapter_id) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (state) {
case WXYZ_DownloadStateChapterDownloadFinished: // 章节下载完成
{
[weakSelf setCollectionCellDownloadStateWithChapter_id:chapter_id downloadState:WXYZ_ProductionDownloadStateDownloaded];
}
break;
case WXYZ_DownloadStateChapterDownloadFail: // 下载失败
{
[weakSelf setCollectionCellDownloadStateWithChapter_id:chapter_id downloadState:WXYZ_ProductionDownloadStateFail];
}
break;
case WXYZ_DownloadStateChapterDownloadStart: // 开始下载
{
[weakSelf setCollectionCellDownloadStateWithChapter_id:chapter_id downloadState:WXYZ_ProductionDownloadStateDownloading];
}
break;
default:
break;
}
[weakSelf reloadToolBar];
});
};
self.audioDownloadManager.downloadMissionStateChangeBlock = ^(WXYZ_DownloadMissionState state, NSInteger production_id, NSArray * _Nonnull chapter_ids) {
SS(strongSelf)
switch (state) {
// 任务开始
case WXYZ_DownloadStateMissionStart:
{
[weakSelf.downloadIndicatorView stopAnimating];
[weakSelf.downloadButton setTitle:TFLocalizedString(@"立即下载") forState:UIControlStateNormal];
for (NSString *t_chapter_id in chapter_ids) {
[weakSelf setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateDownloading];
}
}
break;
// 任务失败
case WXYZ_DownloadStateMissionFail:
{
[weakSelf.downloadIndicatorView stopAnimating];
[weakSelf.downloadButton setTitle:TFLocalizedString(@"立即下载") forState:UIControlStateNormal];
for (NSString *t_chapter_id in chapter_ids) {
[weakSelf setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateNormal];
}
}
break;
case WXYZ_DownloadStateMissionShouldPay:
{
[weakSelf.downloadIndicatorView stopAnimating];
[weakSelf.downloadButton setTitle:TFLocalizedString(@"立即下载") forState:UIControlStateNormal];
if (!weakSelf.payBarShowing) {
weakSelf.payBarShowing = YES;
TFProductionChapterModel *chapterModel = [[TFProductionChapterModel alloc] init];
chapterModel.production_id = production_id;
chapterModel.chapter_ids = chapter_ids;
WXYZ_ChapterBottomPayBar *payBar = [[WXYZ_ChapterBottomPayBar alloc] initWithChapterModel:chapterModel barType:WXYZ_BottomPayBarTypeDownload productionType:TFProductionTypeAudio];
payBar.paySuccessChaptersBlock = ^(NSArray<NSString *> * _Nonnull success_chapter_ids) {
[strongSelf downloadClick];
};
payBar.payFailChaptersBlock = ^(NSArray<NSString *> * _Nonnull fail_chapter_ids) {
for (NSString *t_chapter_id in fail_chapter_ids) {
[weakSelf setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateNormal];
}
[weakSelf reloadToolBar];
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"购买失败")];
};
payBar.payCancleChapterBlock = ^(NSArray<NSString *> * _Nonnull fail_chapter_ids) {
for (NSString *t_chapter_id in fail_chapter_ids) {
[weakSelf setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateNormal];
}
[weakSelf reloadToolBar];
};
SS(strongSelf)
payBar.bottomPayBarHiddenBlock = ^{
strongSelf.payBarShowing = NO;
};
[payBar showBottomPayBar];
}
}
break;
case WXYZ_DownloadStateMissionFinished:
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"下载完成")];
weakSelf.headerTitleLabel.text = [NSString stringWithFormat:TFLocalizedString(@"已下载%zd章"), [[WXYZ_AudioDownloadManager sharedManager] getDownloadChapterCountWithProduction_id:weakSelf.audioModel.production_id]];
break;
default:
break;
}
weakSelf.downloadButton.userInteractionEnabled = YES;
};
}
- (void)downloadClick
{
self.downloadButton.userInteractionEnabled = NO;
NSMutableArray *chapter_ids = [NSMutableArray array];
for (NSString *t_chapter_id in self.selectSourceDictionary.allKeys) {
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateSelected) {
[chapter_ids addObject:t_chapter_id];
}
}
[self.downloadIndicatorView startAnimating];
[self.downloadButton setTitle:@"" forState:UIControlStateNormal];
[self reloadToolBar];
[self.audioDownloadManager downloadChaptersWithProductionModel:self.audioModel production_id:self.audioModel.production_id chapter_ids:chapter_ids];
}
- (void)reloadToolBar
{
NSInteger normalIndex = 0;
NSInteger selectIndex = 0;
NSInteger downloadedIndex = 0;
for (NSString *t_key in self.selectSourceDictionary) {
switch ([[self.selectSourceDictionary objectForKey:t_key] integerValue]) {
case WXYZ_ProductionDownloadStateNormal:
normalIndex ++;
break;
case WXYZ_ProductionDownloadStateDownloaded:
downloadedIndex ++;
break;
case WXYZ_ProductionDownloadStateSelected:
selectIndex ++;
break;
default:
break;
}
}
if (selectIndex > 0) {
memoryBarView.text = [NSString stringWithFormat:TFLocalizedString(@"已选择%@条声音,占用%@/可用空间%@"), [TFUtilsHelper formatStringWithInteger:selectIndex], [TFUtilsHelper convertFileSize:self.totalMemorySize * 1024], [TFUtilsHelper getRemainingMemorySpace]];
[memoryBarView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(memoryBarView.intrinsicContentSize.height);
}];
} else {
memoryBarView.text = [NSString stringWithFormat:@"%@%@", TFLocalizedString(@"可用空间"), [TFUtilsHelper getRemainingMemorySpace]];
[memoryBarView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(memoryBarView.intrinsicContentSize.height);
}];
}
if (downloadedIndex == self.dataSourceArray.count) {
selectAllButton.hidden = YES;
self.downloadButton.enabled = NO;
self.downloadButton.selected = NO;
self.downloadButton.backgroundColor = [UIColor whiteColor];
[self.downloadButton setTitle:TFLocalizedString(@"已全部下载") forState:UIControlStateNormal];
[self.downloadButton setTitleColor:kGrayTextLightColor forState:UIControlStateNormal];
[self.downloadButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.top.mas_equalTo(selectAllButton.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(selectAllButton.mas_height);
}];
return;
}
self.downloadButton.enabled = NO;
self.downloadButton.backgroundColor = kGrayTextLightColor;
[self.downloadButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(SCREEN_WIDTH / 3);
}];
selectAllButton.selected = NO;
selectAllButton.enabled = YES;
selectAllButton.hidden = NO;
selectAllButton.buttonTitle = TFLocalizedString(@"全选");
selectAllButton.buttonImageName = @"audio_download_unselect";
if (selectIndex > 0 && normalIndex == 0) { // 有选中的文件并且没有未选中的文件
self.downloadButton.enabled = YES;
self.downloadButton.backgroundColor = kMainColor;
selectAllButton.selected = YES;
selectAllButton.buttonTitle = TFLocalizedString(@"取消全选");
selectAllButton.buttonImageName = @"audio_download_select";
} else if (normalIndex > 0 && selectIndex > 0) { // 有未选中的文件
self.downloadButton.enabled = YES;
self.downloadButton.backgroundColor = kMainColor;
}
}
- (void)setCollectionCellDownloadStateWithChapter_id:(NSInteger)chapter_id downloadState:(WXYZ_ProductionDownloadState)downloadState
{
WXYZ_AudioDownloadTableViewCell *cell = (WXYZ_AudioDownloadTableViewCell *)[self.mainTableView cellForRowAtIndexPath:(NSIndexPath *)[self.cellIndexDictionary objectForKey:[TFUtilsHelper formatStringWithInteger:chapter_id]]];
cell.cellDownloadState = downloadState;
[self.selectSourceDictionary setObject:[TFUtilsHelper formatStringWithInteger:downloadState] forKey:[TFUtilsHelper formatStringWithInteger:chapter_id]];
}
- (void)netRequest
{
WS(weakSelf)
[TFNetworkTools POST:Audio_Catalog parameters:@{@"audio_id":[TFUtilsHelper formatStringWithInteger:self.production_id]} model:TFProductionModel.class success:^(BOOL isSuccess, TFProductionModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
if (t_model.chapter_list.count > 0) {
weakSelf.audioModel = t_model;
weakSelf.dataSourceArray = [NSMutableArray arrayWithArray:t_model.chapter_list];
[weakSelf resetSelectSourceDicWithDataSourceArray:t_model.chapter_list productionType:TFProductionTypeAudio];
}
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
[weakSelf.mainTableView reloadData];
[weakSelf reloadToolBar];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[weakSelf.mainTableView reloadData];
}];
}
@end
@@ -0,0 +1,19 @@
//
// WXYZ_AudioPlayPageMenuDirectoryTableViewCell.h
// WXReader
//
// Created by Andrew on 2020/3/19.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "TFBasicTableViewCell.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioPlayPageMenuDirectoryTableViewCell : TFBasicTableViewCell
@property (nonatomic, strong) TFProductionChapterModel *chapterListModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,136 @@
//
// WXYZ_AudioPlayPageMenuDirectoryTableViewCell.m
// WXReader
//
// Created by Andrew on 2020/3/19.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioPlayPageMenuDirectoryTableViewCell.h"
#import "TFReadRecordManager.h"
@implementation WXYZ_AudioPlayPageMenuDirectoryTableViewCell
{
UIImageView *leftIcon;
UILabel *chapterNameLabel;
#if TF_Super_Member_Mode && TF_Recharge_Mode
UIImageView *lockIcon;
#endif
}
- (void)createSubviews
{
[super createSubviews];
leftIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"audio_directory_list"]];
leftIcon.userInteractionEnabled = YES;
leftIcon.hidden = YES;
[self.contentView addSubview:leftIcon];
[leftIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kMargin);
make.centerY.mas_equalTo(self.contentView.mas_centerY);
make.width.mas_equalTo(CGFLOAT_MIN);
make.height.mas_equalTo(kGeometricHeight(kLabelHeight / 2, 50, 32));
}];
#if TF_Super_Member_Mode && TF_Recharge_Mode
lockIcon = [[UIImageView alloc] init];
lockIcon.image = [[UIImage imageNamed:@"book_directory_lock"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
lockIcon.tintColor = kColorRGB(139, 140, 146);
lockIcon.hidden = YES;
[self.contentView addSubview:lockIcon];
[lockIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(self.contentView.mas_centerY);
make.height.width.mas_equalTo(15);
}];
#endif
// 章节名称
chapterNameLabel = [[UILabel alloc] init];
chapterNameLabel.textColor = kBlackColor;
chapterNameLabel.font = kMainFont;
chapterNameLabel.textAlignment = NSTextAlignmentLeft;
[self.contentView addSubview:chapterNameLabel];
[chapterNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(leftIcon.mas_right).with.offset(kHalfMargin);
make.top.mas_equalTo(self.contentView.mas_top);
#if TF_Super_Member_Mode && TF_Recharge_Mode
make.right.mas_equalTo(lockIcon.mas_left).with.offset(- 5);
#else
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
#endif
make.height.mas_equalTo(self.contentView.mas_height);
}];
}
- (void)setChapterListModel:(TFProductionChapterModel *)chapterListModel
{
_chapterListModel = chapterListModel;
chapterNameLabel.text = chapterListModel.chapter_title?:@"";
#if TF_Super_Member_Mode && TF_Recharge_Mode
if (chapterListModel.is_preview == 1) {
lockIcon.hidden = NO;
} else {
lockIcon.hidden = YES;
}
#endif
if (chapterListModel.chapter_id == [[TFReadRecordManager shareManagerWithProductionType:self.productionType] getReadingRecordChapter_idWithProduction_id:chapterListModel.production_id]) {
chapterNameLabel.textColor = kMainColor;
leftIcon.hidden = NO;
[leftIcon mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(kLabelHeight / 2);
}];
[chapterNameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(leftIcon.mas_right).with.offset(kHalfMargin);
make.top.mas_equalTo(self.contentView.mas_top);
#if TF_Super_Member_Mode && TF_Recharge_Mode
make.right.mas_equalTo(lockIcon.mas_left).with.offset(- 5);
#else
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
#endif
make.height.mas_equalTo(self.contentView.mas_height);
}];
} else if ([[TFReadRecordManager shareManagerWithProductionType:self.productionType] chapterHasReadedWithProduction_id:chapterListModel.production_id chapter_id:chapterListModel.chapter_id]) {
chapterNameLabel.textColor = kGrayTextColor;
leftIcon.hidden = YES;
[leftIcon mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(CGFLOAT_MIN);
}];
[chapterNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kMargin);
make.top.mas_equalTo(self.contentView.mas_top);
#if TF_Super_Member_Mode && TF_Recharge_Mode
make.right.mas_equalTo(lockIcon.mas_left).with.offset(- 5);
#else
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
#endif
make.height.mas_equalTo(self.contentView.mas_height);
}];
} else {
chapterNameLabel.textColor = kBlackColor;
leftIcon.hidden = YES;
[leftIcon mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(CGFLOAT_MIN);
}];
[chapterNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kMargin);
make.top.mas_equalTo(self.contentView.mas_top);
#if TF_Super_Member_Mode && TF_Recharge_Mode
make.right.mas_equalTo(lockIcon.mas_left).with.offset(- 5);
#else
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
#endif
make.height.mas_equalTo(self.contentView.mas_height);
}];
}
}
@end
@@ -0,0 +1,21 @@
//
// WXYZ_AudioPlayPageMenuTableViewCell.h
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioPlayPageMenuTableViewCell : TFBasicTableViewCell
@property (nonatomic, copy) NSString *cellTitleString;
@property (nonatomic, assign) BOOL cellSelected;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,59 @@
//
// WXYZ_AudioPlayPageMenuTableViewCell.m
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioPlayPageMenuTableViewCell.h"
@implementation WXYZ_AudioPlayPageMenuTableViewCell
{
UILabel *titleLabel;
UIImageView *chooseIndicator;
}
- (void)createSubviews
{
[super createSubviews];
chooseIndicator = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"audio_menu_choose"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
chooseIndicator.userInteractionEnabled = YES;
chooseIndicator.hidden = YES;
chooseIndicator.tintColor = kMainColor;
[self.contentView addSubview:chooseIndicator];
[chooseIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.contentView.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(self.contentView.mas_centerY);
make.width.height.mas_equalTo(20);
}];
titleLabel = [[UILabel alloc] init];
titleLabel.textColor = kBlackColor;
titleLabel.textAlignment = NSTextAlignmentLeft;
titleLabel.font = kMainFont;
[self.contentView addSubview:titleLabel];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kMargin);
make.top.mas_equalTo(self.contentView.mas_top);
make.right.mas_equalTo(chooseIndicator.mas_left).with.offset(- kHalfMargin);
make.bottom.mas_equalTo(self.contentView.mas_bottom);
}];
}
- (void)setCellTitleString:(NSString *)cellTitleString
{
_cellTitleString = cellTitleString;
titleLabel.text = cellTitleString;
}
- (void)setCellSelected:(BOOL)cellSelected
{
_cellSelected = cellSelected;
chooseIndicator.hidden = !cellSelected;
}
@end
@@ -0,0 +1,44 @@
//
// WXYZ_AudioPlayPageMenuView.h
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, WXYZ_MenuType) {
WXYZ_MenuTypeAudioSpeed, // 有声语速
WXYZ_MenuTypeAudioDirectory, // 有声目录
WXYZ_MenuTypeAudioSelection, // 有声选章
WXYZ_MenuTypeAiSpeed, // ai语速
WXYZ_MenuTypeAiVoice, // ai声音
WXYZ_MenuTypeAiDirectory, // ai目录
WXYZ_MenuTypeTiming // 定时
};
@interface WXYZ_AudioPlayPageMenuView : UIView <UIGestureRecognizerDelegate, UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) NSArray *menuListArray;
/// 总章节数量
@property (nonatomic, assign) NSInteger totalChapter;
@property (nonatomic, copy) void (^chooseMenuBlock)(WXYZ_MenuType menuType, NSInteger chooseIndex);
@property (nonatomic, copy) void (^chooseDirectoryMenuBlock)(NSInteger chapter_id, NSInteger chooseIndex);
@property (nonatomic, copy) void (^timingCompleteBlock)(BOOL finish);
- (void)showWithMenuType:(WXYZ_MenuType)menuType;
- (void)close;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,564 @@
//
// WXYZ_AudioPlayPageMenuView.m
// WXReader
//
// Created by Andrew on 2020/3/18.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioPlayPageMenuView.h"
#import "WXYZ_AudioPlayPageMenuTableViewCell.h"
#import "WXYZ_AudioPlayPageMenuDirectoryTableViewCell.h"
#import "TFButton.h"
#import "WXYZ_AudioSettingHelper.h"
#import "TFReadRecordManager.h"
#define Menu_Cell_Height 44
#define Menu_Header_Height 40
#define Menu_Footer_Height (40 + PUB_TABBAR_OFFSET)
@interface WXYZ_AudioPlayPageMenuView ()
/// 是倒序
@property (nonatomic, assign) BOOL isInvert;
@end
@implementation WXYZ_AudioPlayPageMenuView
{
WXYZ_MenuType _menuType;
UITapGestureRecognizer *tap;
UIView *backView;
UITableView *mainTableView;
UIButton *closeButton;
UILabel *headerTitleLabel;
UIView *sectionHeaderView;
UILabel *sectionHeaderTitle;
}
- (instancetype)init
{
if (self = [super init]) {
[self initialize];
[self createSubviews];
}
return self;
}
- (void)initialize
{
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
self.backgroundColor = kBlackTransparentColor;
self.tag = 111;
[kMainWindow addSubview:self];
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(close)];
tap.numberOfTapsRequired = 1;
tap.delegate = self;
[self addGestureRecognizer:tap];
}
- (void)createSubviews
{
backView = [[UIView alloc] init];
backView.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
backView.backgroundColor = kWhiteColor;
[backView addRoundingCornersWithRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight];
[self addSubview:backView];
mainTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
mainTableView.backgroundColor = [UIColor whiteColor];
mainTableView.delegate = self;
mainTableView.dataSource = self;
mainTableView.showsVerticalScrollIndicator = NO;
mainTableView.showsHorizontalScrollIndicator = NO;
mainTableView.estimatedRowHeight = 100;
mainTableView.sectionFooterHeight = 10;
mainTableView.rowHeight = UITableViewAutomaticDimension;
mainTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
if (@available(iOS 11.0, *)) {
mainTableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}
[backView addSubview:mainTableView];
[mainTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(backView.mas_left);
make.top.mas_equalTo(backView.mas_top);
make.width.mas_equalTo(backView.mas_width);
make.height.mas_equalTo(backView.mas_height).offset(-Menu_Footer_Height);
}];
headerTitleLabel = [[UILabel alloc] init];
headerTitleLabel.textAlignment = NSTextAlignmentCenter;
headerTitleLabel.textColor = kBlackColor;
headerTitleLabel.font = kBoldFont15;
headerTitleLabel.backgroundColor = [UIColor whiteColor];
[backView addSubview:headerTitleLabel];
[headerTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(backView.mas_left);
make.top.mas_equalTo(backView.mas_top);
make.width.mas_equalTo(backView.mas_width);
make.height.mas_equalTo(Menu_Header_Height);
}];
{
UIView *line = [[UIView alloc] init];
line.backgroundColor = kGrayLineColor;
[backView addSubview:line];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.bottom.mas_equalTo(headerTitleLabel.mas_bottom);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(kCellLineHeight);
}];
}
closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
closeButton.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, Menu_Footer_Height);
closeButton.backgroundColor = kWhiteColor;
[closeButton setTitle:TFLocalizedString(@"关闭") forState:UIControlStateNormal];
[closeButton setTitleColor:kBlackColor forState:UIControlStateNormal];
[closeButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, PUB_TABBAR_OFFSET, 0)];
[closeButton.titleLabel setFont:kMainFont];
[closeButton addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside];
[backView addSubview:closeButton];
[closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(backView.mas_left);
make.bottom.mas_equalTo(backView.mas_bottom);
make.width.mas_equalTo(backView.mas_width);
make.height.mas_equalTo(Menu_Footer_Height);
}];
{
UIView *line = [[UIView alloc] init];
line.backgroundColor = kGrayLineColor;
[backView addSubview:line];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(closeButton.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(kCellLineHeight);
}];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.menuListArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_menuType == WXYZ_MenuTypeAudioDirectory || _menuType == WXYZ_MenuTypeAiDirectory) {
static NSString *cellName = @"WXYZ_AudioPlayPageMenuDirectoryTableViewCell";
WXYZ_AudioPlayPageMenuDirectoryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_AudioPlayPageMenuDirectoryTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.productionType = _menuType == WXYZ_MenuTypeAiDirectory?TFProductionTypeAi:TFProductionTypeAudio;
cell.chapterListModel = [self.menuListArray objectAtIndex:indexPath.row];
cell.hiddenEndLine = indexPath.row == self.menuListArray.count - 1;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
} else {
static NSString *cellName = @"WXYZ_AudioPlayPageMenuTableViewCell";
WXYZ_AudioPlayPageMenuTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_AudioPlayPageMenuTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.cellTitleString = [self.menuListArray objectAtIndex:indexPath.row];
cell.hiddenEndLine = indexPath.row == self.menuListArray.count - 1;
switch (_menuType) {
case WXYZ_MenuTypeTiming:
cell.cellSelected = [[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == indexPath.row;
break;
case WXYZ_MenuTypeAudioSpeed:
cell.cellSelected = [[WXYZ_AudioSettingHelper sharedManager] getReadSpeedWithProducitionType:TFProductionTypeAudio] == indexPath.row;
break;
case WXYZ_MenuTypeAiSpeed:
cell.cellSelected = [[WXYZ_AudioSettingHelper sharedManager] getReadSpeedWithProducitionType:TFProductionTypeAi] == indexPath.row;
break;
case WXYZ_MenuTypeAiVoice:
cell.cellSelected = [[WXYZ_AudioSettingHelper sharedManager] getReadVoiceWithProducitionType:TFProductionTypeAi] == indexPath.row;
break;
default:
break;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return Menu_Cell_Height;
}
//section头间距
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (_menuType == WXYZ_MenuTypeAudioDirectory || _menuType == WXYZ_MenuTypeAiDirectory) {
return Menu_Header_Height + 40;
}
return Menu_Header_Height;
}
//section头视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (!sectionHeaderView) {
sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, Menu_Header_Height)];
sectionHeaderView.backgroundColor = [UIColor clearColor];
if (_menuType == WXYZ_MenuTypeAudioDirectory || _menuType == WXYZ_MenuTypeAiDirectory) {
sectionHeaderView.backgroundColor = [UIColor whiteColor];
sectionHeaderTitle = [[UILabel alloc] initWithFrame:CGRectMake(kMargin, Menu_Header_Height, SCREEN_WIDTH / 2, 40)];
sectionHeaderTitle.text = [NSString stringWithFormat:TFLocalizedString(@"共%@章"), [TFUtilsHelper formatStringWithInteger:self.totalChapter]];
sectionHeaderTitle.textColor = kGrayTextColor;
sectionHeaderTitle.textAlignment = NSTextAlignmentLeft;
sectionHeaderTitle.font = kFont12;
[sectionHeaderView addSubview:sectionHeaderTitle];
CGFloat width = [TFViewHelper getDynamicWidthWithLabelFont:kFont12 labelHeight:40.0 labelText:TFLocalizedString(@"正序") maxWidth:SCREEN_WIDTH / 2.0];
width += kLabelHeight;
TFButton *sortButton = [[TFButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH - kHalfMargin - width, Menu_Header_Height, width, 40) buttonTitle:TFLocalizedString(@"正序") buttonImageName:@"comic_positive_order" buttonIndicator:TFButtonIndicatorImageRightBothRight];
sortButton.buttonImageScale = 0.3;
sortButton.buttonTitleFont = kFont12;
sortButton.graphicDistance = 5;
sortButton.buttonTitleColor = kGrayTextColor;
sortButton.tag = 0;
[sortButton addTarget:self action:@selector(changeDirectorySort:) forControlEvents:UIControlEventTouchUpInside];
[sectionHeaderView addSubview:sortButton];
}
}
if (sectionHeaderTitle) {
sectionHeaderTitle.text = [NSString stringWithFormat:TFLocalizedString(@"共%@章"), [TFUtilsHelper formatStringWithInteger:self.totalChapter]];
}
return sectionHeaderView;
}
//section底部间距
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return CGFLOAT_MIN;
}
//section底部视图
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, CGFLOAT_MIN)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (_menuType) {
case WXYZ_MenuTypeTiming:
[[WXYZ_AudioSettingHelper sharedManager] setReadTimingWithIndex:indexPath.row];
break;
case WXYZ_MenuTypeAudioSpeed:
[[WXYZ_AudioSettingHelper sharedManager] setReadSpeedWithIndex:indexPath.row producitionType:TFProductionTypeAudio];
break;
case WXYZ_MenuTypeAiSpeed:
[[WXYZ_AudioSettingHelper sharedManager] setReadSpeedWithIndex:indexPath.row producitionType:TFProductionTypeAi];
break;
case WXYZ_MenuTypeAiVoice:
[[WXYZ_AudioSettingHelper sharedManager] setReadVoiceWithIndex:indexPath.row producitionType:TFProductionTypeAi];
break;
default:
break;
}
if (_menuType == WXYZ_MenuTypeAudioDirectory || _menuType == WXYZ_MenuTypeAiDirectory) {
TFProductionChapterModel *listModel = [self.menuListArray objectAtIndex:indexPath.row];
if (listModel.chapter_id > 0) {
if (self.chooseDirectoryMenuBlock) {
self.chooseDirectoryMenuBlock(listModel.chapter_id, indexPath.row);
}
}
} else {
if (self.chooseMenuBlock) {
self.chooseMenuBlock(_menuType, indexPath.row);
}
}
[tableView reloadData];
[self close];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view.tag != 111) {
return NO;
} else {
return YES;
}
}
- (void)changeDirectorySort:(TFButton *)sender
{
if (sender.tag == 0) {
sender.tag = 1;
sender.buttonImageName = @"comic_reverse_order";
sender.buttonTitle = TFLocalizedString(@"倒序");
self.isInvert = YES;
} else {
sender.tag = 0;
sender.buttonImageName = @"comic_positive_order";
sender.buttonTitle = TFLocalizedString(@"正序");
self.isInvert = NO;
}
if (_menuType == WXYZ_MenuTypeAiDirectory) {
TFProductionChapterModel *t_model = self.menuListArray.firstObject;
NSDictionary *params = @{
@"book_id" : @(t_model.production_id),
@"order_by" : sender.tag ? @(2) : @(1)
};
WS(weakSelf)
[TFNetworkTools POST:Book_New_Catalog parameters:params model:TFCatalogModel.class success:^(BOOL isSuccess, TFCatalogModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.totalChapter = t_model.total_chapter;
NSMutableArray<TFProductionChapterModel *> *t_arr = [NSMutableArray array];
for (TFCatalogListModel *list in t_model.list) {
TFProductionChapterModel *model = [[TFProductionChapterModel alloc] init];
model.production_id = [list.book_id integerValue];
model.chapter_id = [list.chapter_id integerValue];
model.next_chapter = [list.next_chapter integerValue];
model.last_chapter = [list.previou_chapter integerValue];
model.chapter_title = list.title;
model.total_words = [list.words integerValue];
model.is_vip = list.vip;
model.update_time = list.update_time;
model.display_order = [NSString stringWithFormat:@"%zd", list.display_order];
model.can_read = list.can_read;
model.is_preview = list.preview;
[t_arr addObject:model];
}
weakSelf.menuListArray = t_arr;
[mainTableView reloadData];
[mainTableView hideRefreshHeader];
[mainTableView showRefreshFooter];
}
} failure:nil];
} else {
self.menuListArray = [[self.menuListArray reverseObjectEnumerator] allObjects];
[mainTableView reloadData];
[mainTableView hideRefreshHeader];
[mainTableView showRefreshFooter];
}
}
- (void)showWithMenuType:(WXYZ_MenuType)menuType
{
_menuType = menuType;
switch (menuType) {
case WXYZ_MenuTypeTiming:
self.menuListArray = [[WXYZ_AudioSettingHelper sharedManager] getReadTimingKeys];
headerTitleLabel.text = TFLocalizedString(@"定时");
break;
case WXYZ_MenuTypeAudioSpeed:
self.menuListArray = [[WXYZ_AudioSettingHelper sharedManager] getReadSpeedKeysWithProducitionType:TFProductionTypeAudio];
headerTitleLabel.text = TFLocalizedString(@"语速");
break;
case WXYZ_MenuTypeAiSpeed:
self.menuListArray = [[WXYZ_AudioSettingHelper sharedManager] getReadSpeedKeysWithProducitionType:TFProductionTypeAi];
headerTitleLabel.text = TFLocalizedString(@"语速");
break;
case WXYZ_MenuTypeAiVoice:
{
self.menuListArray = [[WXYZ_AudioSettingHelper sharedManager] getReadVoiceKeysWithProducitionType:TFProductionTypeAi];
headerTitleLabel.text = TFLocalizedString(@"声音");
}
break;
case WXYZ_MenuTypeAudioDirectory:
case WXYZ_MenuTypeAiDirectory:
{
headerTitleLabel.text = TFLocalizedString(@"章节目录");
WS(weakSelf)
// [mainTableView addFooterRefreshWithRefreshingBlock:^{
// if (weakSelf.isInvert) {
// [weakSelf requestCatalogWithScrollType:@"2"];
// } else {
// [weakSelf requestCatalogWithScrollType:@"1"];
// }
// }];
mainTableView.mj_footer = [MJRefreshFooter footerWithRefreshingBlock:^{
if (weakSelf.isInvert) {
[weakSelf requestCatalogWithScrollType:@"2"];
} else {
[weakSelf requestCatalogWithScrollType:@"1"];
}
}];
}
break;
case WXYZ_MenuTypeAudioSelection:
{
if (self.menuListArray.count > 0) {
NSMutableArray *t_array = [NSMutableArray array];
for (int i = 0; i < (self.menuListArray.count / 30) + (self.menuListArray.count % 30 == 0?0:1); i ++) {
[t_array addObject:[NSString stringWithFormat:@"%@-%@", [TFUtilsHelper formatStringWithInteger:(i * 30 + 1)], [TFUtilsHelper formatStringWithInteger:((i + 1) * 30) <= self.menuListArray.count?((i + 1) * 30):self.menuListArray.count]]];
}
self.menuListArray = [t_array copy];
}
headerTitleLabel.text = TFLocalizedString(@"选章");
}
break;
default:
break;
}
// 计算tableview高度
CGFloat tableViewHeight = self.menuListArray.count * Menu_Cell_Height + Menu_Header_Height + Menu_Footer_Height + ((_menuType == WXYZ_MenuTypeAudioDirectory || _menuType == WXYZ_MenuTypeAiDirectory)?80:0);
if (tableViewHeight > SCREEN_HEIGHT / 2) {
tableViewHeight = SCREEN_HEIGHT / 2;
}
[UIView animateWithDuration:kAnimatedDuration animations:^{
backView.frame = CGRectMake(0, SCREEN_HEIGHT - tableViewHeight, SCREEN_WIDTH, tableViewHeight);
}];
[mainTableView reloadData];
[mainTableView layoutIfNeeded];
if (menuType == WXYZ_MenuTypeAiDirectory) {
// 移动到当前播放位置
for (int i = 0; i < self.menuListArray.count; i ++) {
TFProductionChapterModel *chapter_model = [self.menuListArray objectAtIndex:i];
if (chapter_model.chapter_id == [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] getReadingRecordChapter_idWithProduction_id:chapter_model.production_id]) {
[mainTableView scrollToRow:i inSection:0 atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
} else if (menuType == WXYZ_MenuTypeAudioDirectory) {
// 移动到当前播放位置
for (int i = 0; i < self.menuListArray.count; i ++) {
TFProductionChapterModel *chapter_model = [self.menuListArray objectAtIndex:i];
if (chapter_model.chapter_id == [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAudio] getReadingRecordChapter_idWithProduction_id:chapter_model.production_id]) {
[mainTableView scrollToRow:i inSection:0 atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
}
- (void)close
{
[UIView animateWithDuration:kAnimatedDuration animations:^{
backView.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, backView.height);
} completion:^(BOOL finished) {
for (UIView *v in [self subviews]) {
[v removeFromSuperview];
}
[self removeFromSuperview];
}];
}
// scrollType 1:向下加载;2:向上加载
- (void)requestCatalogWithScrollType:(NSString *)scrollType {
BOOL loadDown = [scrollType isEqualToString:@"1"];
NSString *chapterID = @"";
TFProductionChapterModel *t_model = nil;
if (loadDown) {
t_model = self.menuListArray.lastObject;
chapterID = [NSString stringWithFormat:@"%zd", t_model.next_chapter];
} else {
t_model = self.menuListArray.lastObject;
chapterID = [NSString stringWithFormat:@"%zd", t_model.last_chapter];
}
if ([chapterID isEqualToString:@"0"]) {
[mainTableView endRefreshing];
if (loadDown) {
[mainTableView hideRefreshFooter];
} else {
[mainTableView hideRefreshHeader];
}
return;
}
NSDictionary *params = @{
@"book_id" : @(t_model.production_id),
@"chapter_id" : chapterID,
@"scroll_type" : scrollType,
};
WS(weakSelf)
[TFNetworkTools POST:Book_New_Catalog parameters:params model:TFCatalogModel.class success:^(BOOL isSuccess, TFCatalogModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
[mainTableView endRefreshing];
if (isSuccess) {
weakSelf.totalChapter = t_model.total_chapter;
NSMutableArray<TFProductionChapterModel *> *t_arr = [NSMutableArray array];
for (TFCatalogListModel *list in t_model.list) {
TFProductionChapterModel *model = [[TFProductionChapterModel alloc] init];
model.production_id = [list.book_id integerValue];
model.chapter_id = [list.chapter_id integerValue];
model.next_chapter = [list.next_chapter integerValue];
model.last_chapter = [list.previou_chapter integerValue];
model.chapter_title = list.title;
model.total_words = [list.words integerValue];
model.is_vip = list.vip;
model.update_time = list.update_time;
model.display_order = [NSString stringWithFormat:@"%zd", list.display_order];
model.can_read = list.can_read;
model.is_preview = list.preview;
[t_arr addObject:model];
}
if ([scrollType isEqualToString:@"2"]) {
t_arr = [[[t_arr reverseObjectEnumerator] allObjects] mutableCopy];
}
weakSelf.menuListArray = [weakSelf.menuListArray arrayByAddingObjectsFromArray:t_arr];
[mainTableView reloadData];
[mainTableView endRefreshing];
if ([scrollType isEqualToString:@"1"]) {
if (t_arr.lastObject.next_chapter == 0) {
[mainTableView hideRefreshFooter];
}
if (t_arr.firstObject.last_chapter == 0) {
[mainTableView hideRefreshHeader];
}
} else {
if (t_arr.lastObject.last_chapter == 0) {
[mainTableView hideRefreshFooter];
}
if (t_arr.firstObject.next_chapter == 0) {
[mainTableView hideRefreshHeader];
}
}
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
[mainTableView endRefreshing];
}];
}
@end
@@ -0,0 +1,19 @@
//
// WXYZ_AudioDownloadCacheDetailViewController.h
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "TFDownloadViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioDownloadCacheDetailViewController : TFDownloadViewController
@property (nonatomic, strong) TFProductionModel *audioModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,266 @@
//
// WXYZ_AudioDownloadCacheDetailViewController.m
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadCacheDetailViewController.h"
#import "WXYZ_AudioDownloadTableViewCell.h"
#import "WXYZ_AudioDownloadManager.h"
@interface WXYZ_AudioDownloadCacheDetailViewController () <UITableViewDelegate, UITableViewDataSource>
@end
@implementation WXYZ_AudioDownloadCacheDetailViewController
{
UIButton *deleteButton;
TFButton *selectAllButton;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initialize];
[self createSubviews];
[self netRequest];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setStatusBarDefaultStyle];
}
- (void)initialize
{
[self setNavigationBarTitle:self.navTitle?:TFLocalizedString(@"选择章节")];
}
- (void)createSubviews
{
self.mainTableView.delegate = self;
self.mainTableView.dataSource = self;
self.mainTableView.contentInset = UIEdgeInsetsMake(0, 0, PUB_TABBAR_OFFSET, 0);
[self.view addSubview:self.mainTableView];
[self.mainTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(PUB_NAVBAR_HEIGHT);
make.width.mas_equalTo(self.view.mas_width);
make.height.mas_equalTo(self.view.mas_height).with.offset(- PUB_NAVBAR_HEIGHT - PUB_TABBAR_HEIGHT);
}];
selectAllButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"全选") buttonImageName:@"audio_download_unselect" buttonIndicator:TFButtonIndicatorImageLeftBothLeft];
selectAllButton.buttonTitleColor = kBlackColor;
selectAllButton.buttonTitleFont = kMainFont;
selectAllButton.graphicDistance = 10;
selectAllButton.buttonImageScale = 0.4;
selectAllButton.tag = 0;
selectAllButton.backgroundColor = [UIColor whiteColor];
[selectAllButton addTarget:self action:@selector(checkallClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:selectAllButton];
[selectAllButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMargin);
make.top.mas_equalTo(self.mainTableView.mas_bottom);
make.width.mas_equalTo(100);
make.height.mas_equalTo(PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET);
}];
deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
deleteButton.backgroundColor = kGrayTextLightColor;
deleteButton.enabled = NO;
[deleteButton setTitle:TFLocalizedString(@"删除") forState:UIControlStateNormal];
[deleteButton setTitleColor:kWhiteColor forState:UIControlStateNormal];
[deleteButton.titleLabel setFont:kMainFont];
[deleteButton addTarget:self action:@selector(deleteClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:deleteButton];
[deleteButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.view.mas_right);
make.top.mas_equalTo(selectAllButton.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH / 3);
make.height.mas_equalTo(selectAllButton.mas_height);
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataSourceArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TFProductionChapterModel *chapterModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
static NSString *cellName = @"WXYZ_AudioDownloadTableViewCell";
WXYZ_AudioDownloadTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_AudioDownloadTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.isCacheState = YES;
cell.chapterModel = chapterModel;
cell.cellDownloadState = [[self.selectSourceDictionary objectForKey:[TFUtilsHelper formatStringWithInteger:chapterModel.chapter_id]] integerValue];
cell.hiddenEndLine = self.dataSourceArray.count - 1 == indexPath.row;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 30)];
view.backgroundColor = kGrayViewColor;
UILabel *headerTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(kMargin, 0, SCREEN_WIDTH / 2, 30)];
headerTitleLabel.backgroundColor = [UIColor clearColor];
headerTitleLabel.font = kFont12;
headerTitleLabel.text = [NSString stringWithFormat:TFLocalizedString(@"共%@章"), [TFUtilsHelper formatStringWithInteger:self.dataSourceArray.count]];
headerTitleLabel.textColor = kGrayTextColor;
[view addSubview:headerTitleLabel];
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return CGFLOAT_MIN;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, CGFLOAT_MIN)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TFProductionChapterModel *chapterModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
WXYZ_AudioDownloadTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch (cell.cellDownloadState) {
case WXYZ_ProductionDownloadStateDownloaded:
case WXYZ_ProductionDownloadStateNormal:
[self setCollectionCellDownloadStateWithChapter_id:chapterModel.chapter_id downloadState:WXYZ_ProductionDownloadStateSelected];
[self reloadToolBar];
break;
case WXYZ_ProductionDownloadStateSelected:
[self setCollectionCellDownloadStateWithChapter_id:chapterModel.chapter_id downloadState:WXYZ_ProductionDownloadStateNormal];
[self reloadToolBar];
break;
default:
break;
}
}
- (void)checkallClick:(TFButton *)sender
{
for (NSString *t_chapter_id in self.selectSourceDictionary.allKeys) {
if (!sender.selected) { // 全选状态
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateDownloaded || [[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateNormal) {
[self setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateSelected];
}
} else {
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateSelected) {
[self setCollectionCellDownloadStateWithChapter_id:[t_chapter_id integerValue] downloadState:WXYZ_ProductionDownloadStateNormal];
}
}
}
sender.selected = !sender.selected;
[self reloadToolBar];
}
- (void)deleteClick
{
NSMutableArray *t_deleteArr = [NSMutableArray array];
for (NSString *t_chapter_id in self.selectSourceDictionary.allKeys) {
if ([[self.selectSourceDictionary objectForKey:t_chapter_id] integerValue] == WXYZ_ProductionDownloadStateSelected) {
[t_deleteArr addObject:t_chapter_id];
}
}
WS(weakSelf)
[[WXYZ_AudioDownloadManager sharedManager] removeDownloadChaptersWithProduction_id:self.audioModel.production_id chapter_ids:t_deleteArr];
[WXYZ_AudioDownloadManager sharedManager].downloadDeleteFinishBlock = ^(NSArray * _Nonnull success_chapter_ids, NSArray * _Nonnull fail_chapter) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"删除成功")];
[weakSelf netRequest];
};
}
- (void)reloadToolBar
{
NSInteger selectIndex = 0;
NSInteger downloadedIndex = 0;
for (NSString *t_key in self.selectSourceDictionary) {
switch ([[self.selectSourceDictionary objectForKey:t_key] integerValue]) {
case WXYZ_ProductionDownloadStateDownloaded:
case WXYZ_ProductionDownloadStateNormal:
downloadedIndex ++;
break;
case WXYZ_ProductionDownloadStateSelected:
selectIndex ++;
break;
default:
break;
}
}
deleteButton.enabled = NO;
deleteButton.backgroundColor = kGrayTextLightColor;
selectAllButton.selected = NO;
selectAllButton.enabled = YES;
selectAllButton.buttonTitle = TFLocalizedString(@"全选");
selectAllButton.buttonImageName = @"audio_download_unselect";
if (selectIndex > 0 && downloadedIndex == 0) { // 有选中的文件并且没有未选中的文件
deleteButton.enabled = YES;
deleteButton.backgroundColor = kMainColor;
selectAllButton.selected = YES;
selectAllButton.buttonTitle = TFLocalizedString(@"取消全选");
selectAllButton.buttonImageName = @"audio_download_select";
} else if (downloadedIndex > 0 && selectIndex > 0) { // 有未选中的文件
deleteButton.enabled = YES;
deleteButton.backgroundColor = kMainColor;
}
}
- (void)setCollectionCellDownloadStateWithChapter_id:(NSInteger)chapter_id downloadState:(WXYZ_ProductionDownloadState)downloadState
{
WXYZ_AudioDownloadTableViewCell *cell = (WXYZ_AudioDownloadTableViewCell *)[self.mainTableView cellForRowAtIndexPath:(NSIndexPath *)[self.cellIndexDictionary objectForKey:[TFUtilsHelper formatStringWithInteger:chapter_id]]];
cell.cellDownloadState = downloadState;
[self.selectSourceDictionary setObject:[TFUtilsHelper formatStringWithInteger:downloadState] forKey:[TFUtilsHelper formatStringWithInteger:chapter_id]];
}
- (void)netRequest
{
self.dataSourceArray = [[[WXYZ_AudioDownloadManager sharedManager] getDownloadChapterModelArrayWithProduction_id:self.audioModel.production_id] mutableCopy];
if (self.dataSourceArray.count == 0) {
[self.navigationController popViewControllerAnimated:NO];
return;
}
[self resetSelectSourceDicWithDataSourceArray:[self.dataSourceArray copy] productionType:TFProductionTypeAudio];
[self reloadToolBar];
[self.mainTableView reloadData];
}
@end
@@ -0,0 +1,46 @@
//
// WXYZ_AudioDownloadCacheTableViewCell.h
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^CellSelectBlock)(TFProductionModel *productionModel, NSInteger production_id, NSString *name);
typedef void(^ImageViewSelectBlock)(NSInteger production_id);
typedef void(^ButtonSelectBlock)(TFProductionModel *productionModel);
@interface WXYZ_AudioDownloadCacheTableViewCell : TFBasicTableViewCell
@property (nonatomic, strong) TFProductionModel *productionModel;
@property (nonatomic, copy) CellSelectBlock cellSelectBlock;
@property (nonatomic, copy) ImageViewSelectBlock imageViewSelectBlock;
@property (nonatomic, copy) ButtonSelectBlock buttonSelectBlock;
@property (nonatomic, assign, readonly) BOOL isEditting;
@property (nonatomic, assign, readonly) BOOL isSelected;
/// 选择编辑单元
@property (nonatomic, copy) void(^selecteEdittingCellBlock)(TFProductionModel *productionModel, BOOL isSelected);
- (void)setEditing:(BOOL)editing;
// 强行设置编辑状态
- (void)set_Editting:(BOOL)editting;
// 切换选中状态
- (void)switchSelectedState:(BOOL)state;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,231 @@
//
// WXYZ_AudioDownloadCacheTableViewCell.m
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadCacheTableViewCell.h"
#import "TFReadRecordManager.h"
#import "WXYZ_AudioDownloadManager.h"
#import "TFProductionCoverView.h"
@interface WXYZ_AudioDownloadCacheTableViewCell ()
@property (nonatomic, weak) UIView *mainView;
@property (nonatomic, weak) TFProductionCoverView *coverImageView;
@property (nonatomic, weak) UILabel *titleNameLabel;
@property (nonatomic, weak) UILabel *subTitleLabel;
@property (nonatomic, weak) UIButton *readButton;
@property (nonatomic, weak) UIImageView *selectedView;
@end
@implementation WXYZ_AudioDownloadCacheTableViewCell
- (void)createSubviews
{
[super createSubviews];
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapClick:)]];
UIView *mainView = [[UIView alloc] init];
self.mainView = mainView;
mainView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:mainView];
[mainView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView);
make.left.equalTo(self.contentView).offset(-16.0f);
make.width.equalTo(self.contentView).offset(16.0f);
make.height.equalTo(self.contentView);
}];
UIImageView *selectedView = [[UIImageView alloc] init];
self.selectedView = selectedView;
selectedView.image = [UIImage imageNamed:@"audio_download_unselect"];
[mainView addSubview:selectedView];
[selectedView mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(16.0f);
make.left.equalTo(mainView);
make.centerY.equalTo(mainView);
}];
TFProductionCoverView *coverImageView = [[TFProductionCoverView alloc] initWithProductionType:TFProductionTypeAudio coverDirection:TFProductionCoverDirectionVertical];
self.coverImageView = coverImageView;
coverImageView.tag = 200;
[coverImageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapClick:)]];
[mainView addSubview:coverImageView];
[coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(selectedView.mas_right).with.offset(kHalfMargin);
make.top.mas_equalTo(mainView.mas_top).with.offset(kQuarterMargin);
make.width.mas_equalTo(BOOK_WIDTH_SMALL - kMargin);
make.height.mas_equalTo(kGeometricHeight(BOOK_WIDTH_SMALL - kMargin, 3, 4));
make.bottom.mas_equalTo(mainView.mas_bottom).with.offset(- kQuarterMargin).priorityLow();
}];
UILabel *titleNameLabel = [[UILabel alloc] init];
self.titleNameLabel = titleNameLabel;
titleNameLabel.textColor = kBlackColor;
titleNameLabel.textAlignment = NSTextAlignmentLeft;
titleNameLabel.font = kBoldFont14;
titleNameLabel.numberOfLines = 0;
[mainView addSubview:titleNameLabel];
[titleNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(coverImageView.mas_right).with.offset(kHalfMargin);
make.top.mas_equalTo(coverImageView.mas_top);
make.right.mas_equalTo(mainView.mas_right).offset(-kQuarterMargin);
}];
UILabel *subTitleLabel = [[UILabel alloc] init];
self.subTitleLabel = subTitleLabel;
subTitleLabel.textColor = kGrayTextColor;
subTitleLabel.textAlignment = NSTextAlignmentLeft;
subTitleLabel.font = kFont12;
subTitleLabel.numberOfLines = 0;
[mainView addSubview:subTitleLabel];
[subTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(titleNameLabel);
make.bottom.mas_equalTo(coverImageView.mas_bottom);
}];
UIButton *readButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.readButton = readButton;
readButton.backgroundColor = kMainColor;
readButton.layer.cornerRadius = 12;
[readButton setTitle:TFLocalizedString(@"开始阅读") forState:UIControlStateNormal];
[readButton setTitleColor:kWhiteColor forState:UIControlStateNormal];
[readButton.titleLabel setFont:kFont12];
[readButton addTarget:self action:@selector(readButtonClick) forControlEvents:UIControlEventTouchUpInside];
[mainView addSubview:readButton];
[readButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(mainView.mas_right).with.offset(- kHalfMargin);
make.centerY.mas_equalTo(mainView.mas_centerY);
make.width.mas_equalTo(70);
make.height.mas_equalTo(24);
}];
[titleNameLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.readButton.mas_top).offset(-kQuarterMargin);
}];
[subTitleLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.readButton.mas_bottom).offset(kQuarterMargin);
}];
}
- (void)setProductionModel:(TFProductionModel *)productionModel
{
_productionModel = productionModel;
self.coverImageView.coverImageUrl = productionModel.cover;
self.titleNameLabel.text = productionModel.name ? : @"";
self.subTitleLabel.text = [NSString stringWithFormat:TFLocalizedString(@"%@章/%@章"), [TFUtilsHelper formatStringWithInteger:[[WXYZ_AudioDownloadManager sharedManager] getDownloadChapterCountWithProduction_id:productionModel.production_id]], [TFUtilsHelper formatStringWithInteger:productionModel.total_chapters]];
if ([[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAudio] getReadingRecordChapterTitleWithProduction_id:productionModel.production_id].length > 0) {
[self.readButton setTitle:TFLocalizedString(@"继续收听") forState:UIControlStateNormal];
} else {
[self.readButton setTitle:TFLocalizedString(@"开始收听") forState:UIControlStateNormal];
}
}
- (void)cellTapClick:(UITapGestureRecognizer *)tap
{
if (_isEditting) {
[self switchSelectedState:!_isSelected];
return;
}
if (tap.view.tag == 200) {
if (self.imageViewSelectBlock) {
self.imageViewSelectBlock(_productionModel.production_id);
}
} else {
if (self.cellSelectBlock) {
self.cellSelectBlock(_productionModel, _productionModel.production_id, _productionModel.name);
}
}
}
- (void)readButtonClick
{
if (self.buttonSelectBlock) {
self.buttonSelectBlock(_productionModel);
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)switchSelectedState:(BOOL)state {
UIImage *image = nil;
if (state) {
image = [UIImage imageNamed:@"audio_download_select"];
} else {
image = [UIImage imageNamed:@"audio_download_unselect"];
}
_isSelected = state;
self.selectedView.image = image;
!self.selecteEdittingCellBlock ?: self.selecteEdittingCellBlock(self.productionModel, state);
}
- (void)setEditing:(BOOL)editing {
if (editing && _isEditting == NO) {
self.readButton.hidden = editing;
[UIView animateWithDuration:0.2 animations:^{
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(17.0f);
}];
[self.mainView.superview layoutIfNeeded];
} completion:^(BOOL finished) {
if (finished) {
_isEditting = YES;
}
}];
return;
}
if (!editing && _isEditting == YES) {
self.readButton.hidden = editing;
[UIView animateWithDuration:0.2 animations:^{
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(-16.0f);
}];
[self.mainView.superview layoutIfNeeded];
} completion:^(BOOL finished) {
if (finished) {
_isEditting = NO;
}
}];
return;
}
}
- (void)set_Editting:(BOOL)editting {
if (editting) {
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(17.0f);
}];
} else {
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(-16.0f);
}];
}
[self.mainView.superview layoutIfNeeded];
_isEditting = editting;
}
@end
@@ -0,0 +1,23 @@
//
// WXYZ_AudioDownloadCacheViewController.h
// WXReader
//
// Created by Andrew on 2020/3/21.
// Copyright © 2020 Andrew. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioDownloadCacheViewController : TFBasicViewController
/// 切换编辑状态
@property (nonatomic, copy, readonly) BOOL (^editStateBlock)(void);
@property (nonatomic, copy) void(^changeEditStateBlock)(BOOL status);
@property (nonatomic, assign) BOOL isEditting;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,421 @@
//
// WXYZ_AudioDownloadCacheViewController.m
// WXReader
//
// Created by Andrew on 2020/3/21.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadCacheViewController.h"
#import "WXYZ_AudioDownloadCacheDetailViewController.h"
#import "TFAudioPlayViewController.h"
#import "WXYZ_AudioDownloadCacheTableViewCell.h"
#import "WXYZ_AudioDownloadManager.h"
#import "TFReadRecordManager.h"
#import "UIView+LayoutCallback.h"
#import "TFCollectionManager.h"
@interface WXYZ_AudioDownloadCacheViewController () <UITableViewDelegate, UITableViewDataSource>
/// 编辑页面
@property (nonatomic, weak) UIView *edittingView;
@property (nonatomic, weak) UIButton *edittingAll;
@property (nonatomic, weak) UIButton *edittingDelete;
@property (nonatomic, strong) NSMutableArray<NSNumber *> *selectedArray;
@property (nonatomic, weak) CALayer *topLayer;
@property (nonatomic, weak) CALayer *middleLayer;
@end
@implementation WXYZ_AudioDownloadCacheViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initialize];
[self createSubviews];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setStatusBarDefaultStyle];
self.dataSourceArray = [[[[[WXYZ_DownloadHelper sharedManager] getDownloadProductionArrayWithProductionType:TFProductionTypeAudio] reverseObjectEnumerator] allObjects] mutableCopy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.dataSourceArray.count == 0) {
[self.mainTableView xtfei_showEmptyView];
} else {
[self.mainTableView xtfei_hideEmptyView];
}
});
[self.mainTableView reloadData];
}
- (void)initialize
{
self.selectedArray = [NSMutableArray array];
// 设置编辑状态
WS(weakSelf)
_editStateBlock = ^() {
BOOL isEditting = NO;
if (weakSelf.mainTableView.visibleCells.count == 0) return NO;
for (UITableViewCell *cell in weakSelf.mainTableView.visibleCells) {
if ([cell isMemberOfClass:WXYZ_AudioDownloadCacheTableViewCell.class]) {
WXYZ_AudioDownloadCacheTableViewCell *celll = (WXYZ_AudioDownloadCacheTableViewCell *)cell;
isEditting = !celll.isEditting;
weakSelf.isEditting = isEditting;
// 隐藏/显示底部编辑区域
if (isEditting) {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[weakSelf.edittingView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(weakSelf.view);
}];
[weakSelf.edittingView.superview layoutIfNeeded];
}];
} else {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[weakSelf.edittingView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(weakSelf.view).offset(CGRectGetHeight(weakSelf.edittingView .bounds));
}];
[weakSelf.edittingView.superview layoutIfNeeded];
}];
}
[celll setEditing:!celll.isEditting];
continue;
}
}
return isEditting;
};
[self hiddenNavigationBar:YES];
}
- (void)createSubviews
{
UIView *edittingView = [[UIView alloc] init];
self.edittingView = edittingView;
edittingView .backgroundColor = self.view.backgroundColor;
WS(weakSelf)
edittingView.frameBlock = ^(UIView * _Nonnull view) {
if (weakSelf.topLayer) return;
CALayer *layer = [CALayer layer];
layer.backgroundColor = kColorRGB(238, 238, 238).CGColor;
layer.frame = CGRectMake(0, 0, CGRectGetWidth(view.bounds), 0.5);
[view.layer addSublayer:layer];
weakSelf.topLayer = layer;
};
[self.view addSubview:edittingView ];
[edittingView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.width.bottom.equalTo(self.view);
}];
// 编辑状态下全选按钮
UIButton *edittingAll = [UIButton buttonWithType:UIButtonTypeCustom];
self.edittingAll = edittingAll;
[edittingAll setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal];
[edittingAll addTarget:self action:@selector(selectedAllEvent) forControlEvents:UIControlEventTouchUpInside];
edittingAll.frameBlock = ^(UIButton * _Nonnull button) {
if (weakSelf.middleLayer) return;
CALayer *layer = [CALayer layer];
layer.backgroundColor = kColorRGB(238, 238, 238).CGColor;
layer.frame = CGRectMake(CGRectGetMaxX(button.frame), 16.0f, 0.5, CGRectGetHeight(button.bounds) - 2 * 16.0f);
[button.layer addSublayer:layer];
weakSelf.middleLayer = layer;
};
[edittingAll setTitleColor:kBlackColor forState:UIControlStateNormal];
edittingAll.titleLabel.font = kFont14;
[edittingView addSubview:edittingAll];
[edittingAll mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(edittingView ).offset(1.0f);
make.left.equalTo(edittingView );
make.width.equalTo(edittingView ).multipliedBy(0.5f);
make.height.equalTo(edittingAll.mas_width).multipliedBy(60.0f / 187.5f);
make.bottom.equalTo(edittingView ).offset(-PUB_TABBAR_OFFSET).priorityLow();
}];
// 编辑状态下删除按钮
UIButton *edittingDelete = [UIButton buttonWithType:UIButtonTypeCustom];
self.edittingDelete = edittingDelete;
[edittingDelete setTitle:TFLocalizedString(@"删除") forState:UIControlStateNormal];
[edittingDelete addTarget:self action:@selector(deleteEvent) forControlEvents:UIControlEventTouchUpInside];
[edittingDelete setTitleColor:kGrayTextColor forState:UIControlStateNormal];
edittingDelete.titleLabel.font = kFont14;
[edittingView addSubview:edittingDelete];
[edittingDelete mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.top.equalTo(edittingAll);
make.left.equalTo(edittingAll.mas_right);
}];
[edittingView setNeedsLayout];
[edittingView layoutIfNeeded];
// 设置编辑区域默认高度
[edittingView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.view).offset(CGRectGetHeight(edittingView .bounds));
}];
self.mainTableView.delegate = self;
self.mainTableView.dataSource = self;
self.mainTableView.contentInset = UIEdgeInsetsMake(0, 0, PUB_TABBAR_OFFSET, 0);
[self.view addSubview:self.mainTableView];
[self.mainTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self.view);
make.bottom.equalTo(edittingView .mas_top);
}];
[self setEmptyOnView:self.mainTableView title:TFLocalizedString(@"还没有下载记录") tapBlock:^{
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.dataSourceArray.count == 0) {
[self.mainTableView xtfei_showEmptyView];
} else {
[self.mainTableView xtfei_hideEmptyView];
}
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.mainTableView setEditing:NO animated:YES];
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataSourceArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WS(weakSelf)
WXYZ_AudioDownloadCacheTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"WXYZ_AudioDownloadCacheTableViewCell"];
if (!cell) {
cell = [[WXYZ_AudioDownloadCacheTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"WXYZ_AudioDownloadCacheTableViewCell"];
}
TFProductionModel *t_model = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
cell.productionModel = t_model;
[cell set_Editting:self.isEditting];
cell.cellSelectBlock = ^(TFProductionModel * _Nonnull productionModel, NSInteger production_id, NSString * _Nonnull name) {
productionModel.chapter_list = [[WXYZ_AudioDownloadManager sharedManager] getDownloadChapterModelArrayWithProduction_id:production_id];
WXYZ_AudioDownloadCacheDetailViewController *vc = [[WXYZ_AudioDownloadCacheDetailViewController alloc] init];
vc.audioModel = productionModel;
vc.navTitle = name;
[weakSelf.navigationController pushViewController:vc animated:YES];
};
cell.imageViewSelectBlock = ^(NSInteger production_id) {
TFAudioDetailViewController *vc = [[TFAudioDetailViewController alloc] init];
vc.audio_id = production_id;
[weakSelf.navigationController pushViewController:vc animated:YES];
};
cell.buttonSelectBlock = ^(TFProductionModel * _Nonnull productionModel) {
[[TFCollectionManager shareManagerWithProductionType:TFProductionTypeAudio] moveCollectionToTopWithProductionModel:t_model];
TFAudioPlayViewController *vc = [TFAudioPlayViewController sharedManager];
[vc loadDataWithAudio_id:productionModel.production_id chapter_id:0];
TFNavigationController *nav = [[TFNavigationController alloc] initWithRootViewController:vc];
[[TFViewHelper getWindowRootController] presentViewController:nav animated:YES completion:nil];
};
if ([self.selectedArray containsObject:@(t_model.production_id)]) {
[cell switchSelectedState:YES];
} else {
[cell switchSelectedState:NO];
}
cell.selecteEdittingCellBlock = ^(TFProductionModel * _Nonnull productionModel, BOOL isSelected) {
if (isSelected) {
[weakSelf.selectedArray addObject:@(productionModel.production_id)];
} else {
[weakSelf.selectedArray removeObject:@(productionModel.production_id)];
}
[weakSelf updateEdittingView];
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return TFLocalizedString(@"删除");
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return kHalfMargin;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, kHalfMargin)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return CGFLOAT_MIN;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, PUB_TABBAR_OFFSET == 0 ? 10 : PUB_TABBAR_OFFSET)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
TFProductionModel *t_model = [self.dataSourceArray objectOrNilAtIndex:indexPath.row];
[[WXYZ_AudioDownloadManager sharedManager] removeDownloadProductionWithProduction_id:t_model.production_id];
[self.dataSourceArray removeObject:t_model];
[self.mainTableView reloadData];
if (self.dataSourceArray.count > 0) {
[self.mainTableView xtfei_hideEmptyView];
} else {
[self.mainTableView xtfei_showEmptyView];
}
}
// 全选按钮点击事件
- (void)selectedAllEvent {
if ([self.edittingAll.titleLabel.text isEqualToString:TFLocalizedString(@"全选")]) {
for (UITableViewCell *cell in self.mainTableView.visibleCells) {
if ([cell isMemberOfClass:WXYZ_AudioDownloadCacheTableViewCell.class]) {
WXYZ_AudioDownloadCacheTableViewCell *tempCell = (WXYZ_AudioDownloadCacheTableViewCell *)cell;
[tempCell switchSelectedState:YES];
}
}
for (TFProductionModel *t_model in self.dataSourceArray) {
if (![self.selectedArray containsObject:@(t_model.production_id)]) {
[self.selectedArray addObject:@(t_model.production_id)];
}
}
} else {
for (UITableViewCell *cell in self.mainTableView.visibleCells) {
if ([cell isMemberOfClass:WXYZ_AudioDownloadCacheTableViewCell.class]) {
WXYZ_AudioDownloadCacheTableViewCell *tempCell = (WXYZ_AudioDownloadCacheTableViewCell *)cell;
[tempCell switchSelectedState:NO];
}
}
[self.selectedArray removeAllObjects];
}
[self updateEdittingView];
}
// 删除按钮点击事件
- (void)deleteEvent
{
if (self.selectedArray.count == 0) return;
NSMutableArray *arr = [self.dataSourceArray mutableCopy];
NSMutableArray<NSIndexPath *> *pathArr = [NSMutableArray array];
[arr enumerateObjectsUsingBlock:^(TFProductionModel * _Nonnull productionModel, NSUInteger idx, BOOL * _Nonnull stop) {
if ([self.selectedArray containsObject:@(productionModel.production_id)]) {
[[WXYZ_AudioDownloadManager sharedManager] removeDownloadProductionWithProduction_id:productionModel.production_id];
[self.dataSourceArray removeObject:productionModel];
[self.selectedArray removeObject:@(productionModel.production_id)];
[pathArr addObject:[NSIndexPath indexPathForRow:idx inSection:0]];
}
}];
if (@available(iOS 11.0, *)) {
[self.mainTableView performBatchUpdates:^{
[self.mainTableView deleteRowsAtIndexPaths:pathArr withRowAnimation:UITableViewRowAnimationLeft];
} completion:^(BOOL finished) {
if (!finished) return;
BOOL a = !_editStateBlock ?: _editStateBlock();
NSLog(@"%@", a?@"":@"");
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.edittingView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.view).offset(CGRectGetHeight(self.edittingView .bounds));
}];
[self.edittingView.superview layoutIfNeeded];
}];
!self.changeEditStateBlock ?: self.changeEditStateBlock(YES);
}];
} else {
[self.mainTableView beginUpdates];
[self.mainTableView deleteRowsAtIndexPaths:pathArr withRowAnimation:UITableViewRowAnimationLeft];
[self.mainTableView endUpdates];
dispatch_async(dispatch_get_main_queue(), ^{
BOOL a = !_editStateBlock ?: _editStateBlock();
NSLog(@"%@", a?@"":@"");
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.edittingView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.view).offset(CGRectGetHeight(self.edittingView .bounds));
}];
[self.edittingView.superview layoutIfNeeded];
}];
!self.changeEditStateBlock ?: self.changeEditStateBlock(YES);
});
}
if (self.dataSourceArray.count > 0) {
[self.mainTableView xtfei_hideEmptyView];
} else {
[self.mainTableView xtfei_showEmptyView];
}
self.isEditting = NO;
[self updateEdittingView];
}
// 更新底部编辑区域
- (void)updateEdittingView
{
if (self.dataSourceArray.count > 0 && self.mainTableView.visibleCells.count == 0) return;
BOOL allSelected = YES;
for (TFProductionModel *t_model in self.dataSourceArray) {
if (![self.selectedArray containsObject:@(t_model.production_id)]) {
allSelected = NO;
break;
}
}
if (allSelected) {
[self.edittingAll setTitle:TFLocalizedString(@"取消全选") forState:UIControlStateNormal];
} else {
[self.edittingAll setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal];
}
if (self.selectedArray.count == 0) {
[self.edittingDelete setTitle:TFLocalizedString(@"删除") forState:UIControlStateNormal];
[self.edittingDelete setTitleColor:kGrayTextColor forState:UIControlStateNormal];
} else {
[self.edittingDelete setTitle:[NSString stringWithFormat:@"%@(%zd)", TFLocalizedString(@"删除"), self.selectedArray.count] forState:UIControlStateNormal];
[self.edittingDelete setTitleColor:kRedColor forState:UIControlStateNormal];
}
}
@end
@@ -0,0 +1,30 @@
//
// TFAdvertModel.h
// WXReader
//
// Created by 谢腾飞 on 2020/12/1.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TFAdvertModel : NSObject
#pragma mark 广告相关
@property (nonatomic ,assign) NSUInteger advert_id; // 广告id
@property (nonatomic ,assign) NSUInteger ad_url_type; // 跳转类型 1 内部 2 外部
@property (nonatomic ,copy) NSString *ad_title; // 广告标题
@property (nonatomic ,copy) NSString *ad_image; // 广告图片
@property (nonatomic ,copy) NSString *ad_skip_url; // 广告跳转地址
@property (nonatomic ,copy) NSString *ad_key;
@property (nonatomic ,assign) NSUInteger ad_type; // 广告类型 0 不显示 1 内部广告 2 穿山甲广告
@property (nonatomic ,assign) NSInteger ad_width;
@property (nonatomic ,assign) NSInteger ad_height;
// 当前时间戳
@property (nonatomic ,copy) NSString *timestamp;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,19 @@
//
// TFAdvertModel.m
// WXReader
//
// Created by 谢腾飞 on 2020/12/1.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFAdvertModel.h"
@implementation TFAdvertModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{
@"timestamp" : @"time"
};
}
@end
@@ -0,0 +1,23 @@
//
// TFBannerModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TFBannerModel : NSObject
@property (nonatomic ,copy) NSString *content; // 根据动作类型对于的漫画则为漫画id
@property (nonatomic ,copy) NSString *name; //作品名
@property (nonatomic ,copy) NSString *image; // 封面
@property (nonatomic ,copy) NSString *color; // 封面的背景色
@property (nonatomic ,assign) NSInteger action; // 动作类型, 1:跳漫画,2:scheme跳转,3:外部链接
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,29 @@
//
// TFBannerModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFBannerModel.h"
@implementation TFBannerModel
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{
@"content" :@[@"book_id", @"content"]
};
}
- (NSString *)color
{
if ([_color hasPrefix:@"#"]) {
if (_color.length >= 7) {
return [_color substringWithRange:NSMakeRange(0, 7)];
}
}
return @"#000000";
}
@end
@@ -0,0 +1,31 @@
//
// TFBookMarkModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TFBookMarkModel : NSObject
/// 书籍ID
@property (nonatomic ,copy) NSString *bookID;
/// 书签页内容
@property (nonatomic ,copy) NSString *pageContent;
/// 章节标题
@property (nonatomic ,copy) NSString *chapterTitle;
/// 章节id
@property (nonatomic ,copy) NSString *chapterID;
/// 章节排序
@property (nonatomic ,assign) NSInteger chapterSort;
/// 章节内容索引
@property (nonatomic ,assign) NSInteger specificIndex;
/// 书签加入时间戳
@property (nonatomic ,copy) NSString *timestamp;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,24 @@
//
// TFBookMarkModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFBookMarkModel.h"
@implementation TFBookMarkModel
- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:self.class]) return NO;
return [self hash] == [object hash];
}
- (NSUInteger)hash
{
return [self modelHash];
}
@end
@@ -0,0 +1,83 @@
//
// TFCatalogModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFCatalogListModel, TFCatalogAuthorModel;
@interface TFCatalogModel : NSObject
@property (nonatomic ,assign) NSInteger total_chapter;
@property (nonatomic ,strong) TFCatalogAuthorModel *author;
@property (nonatomic ,copy) NSArray<TFCatalogListModel *> *list;
@end
@interface TFCatalogAuthorModel : NSObject
@property (nonatomic ,copy) NSString *author_name;
@property (nonatomic ,copy) NSString *author_note;
@property (nonatomic ,assign) NSInteger author_id;
@property (nonatomic ,copy) NSString *author_avatar;
@end
@interface TFCatalogListModel : NSObject
/// 章节id
@property (nonatomic ,copy) NSString *chapter_id;
/// 下一章章节id
@property (nonatomic ,copy) NSString *next_chapter;
/// 上一章章节id
@property (nonatomic ,copy) NSString *previou_chapter;
@property (nonatomic ,copy) NSString *book_id;
/// 章节标题
@property (nonatomic ,copy) NSString *title;
/// 字数
@property (nonatomic ,copy) NSString *words;
@property (nonatomic ,assign ,getter = isVip) BOOL vip;
/// 章节更新时间:时间戳
@property (nonatomic ,copy) NSString *update_time;
@property (nonatomic ,copy) NSString *tab;
/// tab颜色,默认是16进制色值
@property (nonatomic ,copy) NSString *color;
/// 当前章节在整个章节中的顺序
@property (nonatomic ,assign) NSInteger display_order;
@property (nonatomic ,assign) BOOL can_read;
@property (nonatomic ,assign ,getter = isPreview) BOOL preview;
@property (nonatomic ,copy) NSString *author_note;
@property (nonatomic ,assign) NSInteger comment_num;
@property (nonatomic ,assign) NSInteger ticket_num;
@property (nonatomic ,assign) NSInteger reward_num;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,59 @@
//
// TFCatalogModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFCatalogModel.h"
@implementation TFCatalogModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass
{
return @{
@"list" : TFCatalogListModel.class,
@"author" : TFCatalogAuthorModel.class
};
}
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{
@"list" : @"chapter_list"
};
}
@end
@implementation TFCatalogAuthorModel
@end
@implementation TFCatalogListModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{
@"title" : @"chapter_title",
@"vip" : @"is_vip",
@"preview" : @"is_preview",
@"previou_chapter" : @"last_chapter"
};
}
- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:self.class]) return NO;
return [self hash] == [object hash];
}
- (NSUInteger)hash
{
return [self.chapter_id hash];
}
@end
@@ -0,0 +1,102 @@
//
// TFCheckSettingModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class AdStatusSetting, SystemSetting, VersionUpdate, StartPage, TFProtocolListModel;
@interface TFCheckSettingModel : NSObject
@property (nonatomic ,strong) AdStatusSetting *ad_status_setting;
@property (nonatomic ,strong) SystemSetting *system_setting;
@property (nonatomic ,strong) VersionUpdate *version_update;
@property (nonatomic ,strong) StartPage *start_page;
/** 微信获取 access_token 的方法前缀 */
@property (nonatomic ,copy) NSString *wechatTokenURL;
@property (nonatomic ,strong) TFProtocolListModel *protocol_list;
@end
@interface AdStatusSetting : NSObject
@property (nonatomic ,assign) BOOL chapter_read_end; // 章节阅读末尾是否开启
@property (nonatomic ,assign) BOOL chapter_read_bottom; // 章节阅读器底部是否开启
@property (nonatomic ,assign) BOOL comic_read_end; // 漫画章节末尾
/// 激励视频广告开关
@property (nonatomic ,assign) BOOL video_ad_switch;
/// 激励视频展示文字
@property (nonatomic ,copy) NSString *video_ad_text;
/// 免广告总时长
@property (nonatomic ,assign) NSInteger ad_free_time;
/// 隔X页插入广告
@property (nonatomic ,assign) NSInteger ad_page_num;
@end
@interface SystemSetting : NSObject
@property (nonatomic ,assign) NSInteger check_status; // 过审状态开关 1-开启 0-关闭
@property (nonatomic ,strong) NSArray <NSString *>*site_type; // 新版UI状态,1:小说,2:漫画,3:有声
@property (nonatomic ,copy) NSString *currencyUnit; // 主货币
@property (nonatomic ,copy) NSString *subUnit; // 子货币
@property (nonatomic ,copy) NSString *vip_send_switch; // 是否开启注册送会员弹框 1 开 2 关
@property (nonatomic ,copy) NSString *project_type; // 项目状态 是否展示漫画小说
@property (nonatomic ,assign) NSInteger ai_switch; // ai读书开关 1 开 2 关
@property (nonatomic ,assign) NSInteger novel_reward_switch; // 阅读器打赏显示开关 1开
@property (nonatomic ,assign) NSInteger monthly_ticket_switch; // 阅读器月票显示开关 1开
@end
@interface VersionUpdate : NSObject
@property (nonatomic ,assign) NSInteger status; // 更新状态 1 弱更新 2 强更新
@property (nonatomic ,copy) NSString *msg; // 更新文案
@property (nonatomic ,copy) NSString *url; // 更新跳转链接
@end
@interface StartPage : NSObject
@property (nonatomic ,copy) NSString *title; // 广告标题
@property (nonatomic ,copy) NSString *content; // 广告内容
@property (nonatomic ,copy) NSString *image; // 自带广告展示图片地址
@property (nonatomic ,assign) NSInteger skip_type; // 点击跳转类型 1 - 跳转小说 2 - 应用内打开链接 3 - 跳转漫画 4 - 浏览器打开链接 5 - 穿山甲广告 6 - 谷歌广告 7 - 广点通广告 8 - 跳转有声
@property (nonatomic ,copy) NSString *ad_key; // 开屏广告key
@end
@interface TFProtocolListModel : NSObject
/// 用户服务协议
@property (nonatomic ,copy) NSString *notify;
/// 隐私政策
@property (nonatomic ,copy) NSString *privacy;
/// 注销协议
@property (nonatomic ,copy) NSString *logoff;
/// 用户协议
@property (nonatomic ,copy) NSString *user;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,119 @@
//
// TFCheckSettingModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFCheckSettingModel.h"
@implementation TFCheckSettingModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{
@"ad_status_setting" : [AdStatusSetting class],
@"system_setting" : [SystemSetting class],
@"version_update" : [VersionUpdate class],
@"start_page" : [StartPage class],
@"protocol_list" : TFProtocolListModel.class
};
}
+ (NSDictionary *)modelCustomPropertyMapper {
return @{
@"wechatTokenURL" : @"wechat_api_url"
};
}
@end
@implementation AdStatusSetting
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{
@"ad_page_num" : @"book_read_gap"
};
}
- (BOOL)chapter_read_bottom
{
if ([TFNetworkManager networkingStatus]) {
return _chapter_read_bottom;
} else {
return NO;
}
}
- (BOOL)chapter_read_end
{
if ([TFNetworkManager networkingStatus]) {
return _chapter_read_end;
} else {
return NO;
}
}
@end
@implementation SystemSetting
@end
@implementation VersionUpdate
@end
@implementation StartPage
@end
@implementation TFProtocolListModel
- (NSString *)user {
if (_user) {
if ([_user containsString:@"?"]) {
return [_user stringByAppendingFormat:@"&language=%@", TFLanguageManager.serverLocalized];
} else {
return [_user stringByAppendingFormat:@"?language=%@", TFLanguageManager.serverLocalized];
}
}
return nil;
}
- (NSString *)logoff {
if (_logoff) {
if ([_privacy containsString:@"?"]) {
return [_logoff stringByAppendingFormat:@"&language=%@", TFLanguageManager.serverLocalized];
} else {
return [_logoff stringByAppendingFormat:@"?language=%@", TFLanguageManager.serverLocalized];
}
}
return nil;
}
- (NSString *)privacy {
if (_privacy) {
if ([_privacy containsString:@"?"]) {
return [_privacy stringByAppendingFormat:@"&language=%@", TFLanguageManager.serverLocalized];
} else {
return [_privacy stringByAppendingFormat:@"?language=%@", TFLanguageManager.serverLocalized];
}
}
return nil;
}
- (NSString *)notify {
if (_notify) {
if ([_notify containsString:@"?"]) {
return [_notify stringByAppendingFormat:@"&language=%@", TFLanguageManager.serverLocalized];
} else {
return [_notify stringByAppendingFormat:@"?language=%@", TFLanguageManager.serverLocalized];
}
}
return nil;
}
@end
@@ -0,0 +1,26 @@
//
// TFPagingModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TFPagingModel : NSObject
// 总页数
@property (nonatomic ,assign) NSInteger current_page;
// 当前页数
@property (nonatomic ,assign) NSInteger total_page;
// 全部页总数量
@property (nonatomic ,assign) NSInteger total_count;
// 当前页总数量
@property (nonatomic ,assign) NSInteger page_size;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,13 @@
//
// TFPagingModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFPagingModel.h"
@implementation TFPagingModel
@end
@@ -0,0 +1,119 @@
//
// TFProductionChapterModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFImageListModel;
@interface TFProductionChapterModel : NSObject
/*
公共使用区域
**/
@property (nonatomic ,assign) NSInteger production_id; // 作品id
@property (nonatomic ,assign) NSInteger chapter_id; // 章节id
@property (nonatomic ,strong) NSArray <NSString *>* chapter_ids; // 章节合集
@property (nonatomic ,assign) NSInteger relation_production_id; // 关联作品id
@property (nonatomic ,copy) NSString *name; // 作品名称
@property (nonatomic ,copy) NSString *chapter_title; // 章节标题
@property (nonatomic ,copy) NSString *subtitle; // 章节子标题
@property (nonatomic ,assign) NSInteger total_words; // 全部字数
@property (nonatomic ,copy) NSString *cover; // 封面
@property (nonatomic ,assign) NSInteger is_preview; // 是否预览内容 1-是 0-不是
@property (nonatomic ,copy) NSString *display_order; // 章节序号
@property (nonatomic ,assign) NSInteger last_chapter; // 上一章节id 没有上一章时返回0
@property (nonatomic ,assign) NSInteger next_chapter; // 下一章id 没有下一章时返回0
@property (nonatomic ,copy) NSString *play_num; // 观看次数
@property (nonatomic ,assign) NSInteger hot_num; // 热度值
@property (nonatomic ,assign) BOOL is_vip; // 是否是vip可观看
@property (nonatomic ,assign) BOOL can_read; // 是否可读
@property (nonatomic ,copy) NSString *update_time; // 章节更新时间
@property (nonatomic ,strong) TFTagModel *tag; // 标签
@property (nonatomic ,strong) TFAdvertModel *advert; // 广告
/// 总章节数
@property (nonatomic ,assign) NSInteger total_chapters;
/*
小说专属
**/
@property (nonatomic ,copy) NSString *content; // 章节内容
@property (nonatomic ,copy) NSString *author_note; // 章节作者寄语
@property (nonatomic ,copy) NSString *comment_num; // 评论数,为Null时不展示
@property (nonatomic ,copy) NSString *ticket_num; // 月票数,为Null时不展示
@property (nonatomic ,copy) NSString *reward_num; // 打赏数,为Null时不展示
/*
漫画专属
**/
@property (nonatomic ,assign) NSInteger vip_images; // 会员章节数
@property (nonatomic ,assign) NSInteger free_image_num; // 免费阅读图片数
@property (nonatomic ,assign) NSInteger total_images; // 全部图片数
@property (nonatomic ,assign) NSInteger total_comment; // 总评论数
@property (nonatomic ,copy) NSString *display_label; // 序号标题
@property (nonatomic ,strong) NSArray <TFImageListModel *>*image_list; // 图片合集
/*
有声专属
**/
@property (nonatomic ,copy) NSString *duration_time; // 音频时长
@property (nonatomic ,assign) NSInteger duration_second; // 音频时长 秒
@property (nonatomic ,assign) CGFloat size; // 音频文件大小 单位:KB
@end
@interface TFImageListModel : NSObject
@property (nonatomic ,assign) NSInteger image_id;
@property (nonatomic ,copy) NSString *image;
@property (nonatomic ,assign) NSInteger width;
@property (nonatomic ,assign) NSInteger height;
@property (nonatomic ,assign) NSInteger image_update_time;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,50 @@
//
// TFProductionChapterModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFProductionChapterModel.h"
@implementation TFProductionChapterModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass
{
return @{@"tag" : [TFTagModel class],
@"advert" : [TFAdvertModel class],
@"image_list" : [TFImageListModel class]
};
}
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{
@"production_id":@[@"book_id", @"comic_id", @"audio_id"],
@"relation_production_id":@"relation_book_id",
@"total_words":@"words",
@"name" :@[@"name", @"title", @"book_name", @"comic_name", @"audio_name"],
@"cover":@[@"cover", @"small_cover"]
};
}
- (void)setAuthor_note:(NSString *)author_note
{
_author_note = author_note;
}
@end
@implementation TFImageListModel
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{
@"image_update_time":@"update_time"
};
}
@end
@@ -0,0 +1,22 @@
//
// TFProductionListModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TFPagingModel.h"
NS_ASSUME_NONNULL_BEGIN
@class TFProductionModel;
@interface TFProductionListModel : TFPagingModel
@property (nonatomic ,strong) NSArray <TFProductionModel *>*list;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,18 @@
//
// TFProductionListModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFProductionListModel.h"
@implementation TFProductionListModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass
{
return @{@"list" : [TFProductionModel class]};
}
@end
@@ -0,0 +1,86 @@
//
// TFProductionModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TFAdvertModel.h"
#import "TFCatalogModel.h"
NS_ASSUME_NONNULL_BEGIN
@class TFTagModel, TFProductionChapterModel;
@interface TFProductionModel : TFAdvertModel <NSCopying>
@property (nonatomic ,assign) NSInteger production_id; // 作品id
@property (nonatomic ,assign) NSUInteger log_id; // 阅读记录id
@property (nonatomic ,copy) NSString *name; // 作品名
@property (nonatomic ,copy) NSString *flag; // 作品角标
@property (nonatomic ,copy) NSString *cover; // 封面
@property (nonatomic ,copy) NSString *horizontal_cover; // 横封面
@property (nonatomic ,copy) NSString *vertical_cover; // 竖封面
@property (nonatomic ,copy) NSString *author; // 作者
@property (nonatomic ,copy) NSString *author_name; // 作品封面作家名称
@property (nonatomic ,copy) NSString *author_note; // 作品封面作家的话
@property (nonatomic ,assign) NSInteger author_id; // 作品封面作家id
@property (nonatomic ,copy) NSString *author_avatar; // 作品封面作家头像
@property (nonatomic ,copy) NSString *finished; // 连载状态
@property (nonatomic ,copy) NSString *visited; // 访问数
@property (nonatomic ,copy) NSString *total_favors; // 全部收藏数
@property (nonatomic ,assign) NSInteger free_chapters; // 免费章节数
@property (nonatomic ,assign) NSInteger total_comment; // 作品评论人数
@property (nonatomic ,copy) NSString *issue_time; // 发布时间
@property (nonatomic ,copy) NSString *hot_num; // 热度值
@property (nonatomic ,copy) NSString *production_descirption; // 作品简介
@property (nonatomic ,copy) NSString *last_chapter_time; // 最新更新时间
@property (nonatomic ,copy) NSString *last_chapter; //最新章节名
@property (nonatomic ,copy) NSString *record_title; // 阅读记录章节名称
@property (nonatomic ,assign) NSInteger total_chapters; // 全部章节数
@property (nonatomic ,assign) BOOL is_readed; // 是否已读
@property (nonatomic ,assign) BOOL is_baoyue; // 是否是vip作品
@property (nonatomic ,assign) BOOL is_recommend; // 是否是推荐作品
@property (nonatomic ,assign) NSString *display_no; // 榜单列表用于排序使用(只有榜单列表会使用)
@property (nonatomic ,assign) TFProductionType productionType; // 作品类别
@property (nonatomic ,strong) NSArray <TFProductionChapterModel *> *chapter_list; // 章节目录
@property (nonatomic ,copy) NSArray<TFCatalogListModel *> *list; // 新章节目录
@property (nonatomic ,strong) NSArray <TFTagModel *> *tag; // 作品标签 没有标签时为空数组
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,46 @@
//
// TFProductionModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFProductionModel.h"
@implementation TFProductionModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass
{
return @{
@"tag" : [TFTagModel class],
@"chapter_list" : [TFProductionChapterModel class],
@"list" : [TFCatalogListModel class],
};
}
+ (NSDictionary *)modelCustomPropertyMapper
{
return @{
@"production_descirption" :@"description",
@"visited" :@"view",
@"record_title" :@"chapter_title",
@"production_id" :@[@"book_id", @"comic_id", @"audio_id"],
@"name" :@[@"name", @"title", @"book_name", @"comic_name", @"audio_name"],
@"total_chapters" :@[@"total_chapters", @"total_chapter"]
};
}
- (id)copyWithZone:(NSZone *)zone
{
return [self modelCopy];
}
- (NSString *)production_descirption
{
_production_descirption = [_production_descirption stringByReplacingOccurrencesOfString:@"\r" withString:@""];
return _production_descirption;
}
@end
@@ -0,0 +1,25 @@
//
// TFSignModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFProductionModel;
@interface TFSignModel : NSObject
@property (nonatomic ,copy) NSString *award;
@property (nonatomic ,copy) NSString *sign_days;
@property (nonatomic ,copy) NSString *tomorrow_award;
@property (nonatomic ,strong) NSArray <TFProductionModel *> *book;
@property (nonatomic ,strong) NSArray <TFProductionModel *> *comic;
@property (nonatomic ,strong) NSArray <TFProductionModel *> *audio;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,21 @@
//
// TFSignModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFSignModel.h"
@implementation TFSignModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass
{
return @{@"book" : [TFProductionModel class],
@"comic" : [TFProductionModel class],
@"audio" : [TFProductionModel class]
};
}
@end
@@ -0,0 +1,21 @@
//
// TFTagModel.h
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TFTagModel : NSObject
@property (nonatomic ,copy) NSString *color;
@property (nonatomic ,copy) NSString *tab;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,13 @@
//
// TFTagModel.m
// TFReader
//
// Created by 谢腾飞 on 2020/12/11.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFTagModel.h"
@implementation TFTagModel
@end
@@ -0,0 +1,18 @@
//
// WXYZ_BookAiPlayPageHeaderView.h
// WXReader
//
// Created by Andrew on 2020/3/11.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TFBasicVoiceHeaderView.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_BookAiPlayPageHeaderView : TFBasicVoiceHeaderView
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,316 @@
//
// WXYZ_BookAiPlayPageHeaderView.m
// WXReader
//
// Created by Andrew on 2020/3/11.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookAiPlayPageHeaderView.h"
#import "TFAudioPlayViewController.h"
#import "TFReaderBookManager.h"
#import "TFReadRecordManager.h"
#import "WXYZ_AudioSettingHelper.h"
#import "WXYZ_PlayingInfoCenter.h"
#import "WXYZ_TouchAssistantView.h"
#import "WXYZ_Player.h"
#if __has_include(<iflyMSC/IFlyMSC.h>)
#import "iflyMSC/IFlyMSC.h"
#endif
@interface WXYZ_BookAiPlayPageHeaderView () <WXYZ_PlayingInfoCenterDelegate
#if __has_include(<iflyMSC/IFlyMSC.h>)
, IFlySpeechSynthesizerDelegate
#endif
>
// 分割字符,讯飞只能解析8000字符,把小说章节内容拆分为数组解析
@property (nonatomic, strong) NSMutableArray __block *segmentCharacterArray;
#if __has_include(<iflyMSC/IFlyMSC.h>)
@property (nonatomic, strong) IFlySpeechSynthesizer *iFlySpeechSynthesizer;
#endif
@end
@implementation WXYZ_BookAiPlayPageHeaderView
#if __has_include(<iflyMSC/IFlyMSC.h>)
- (void)createSubviews
{
[super createSubviews];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(relationViewTitleChange) name:Notification_Change_Audio_Chapter object:nil];
[WXYZ_PlayingInfoCenter sharedManager].delegate = self;
WS(weakSelf)
self.resetPlayerBlock = ^(BOOL immediateReset) {
if (immediateReset) {
[weakSelf initIFlySpeech];
} else if (weakSelf.segmentCharacterArray.count == 0) {
[weakSelf initIFlySpeech];
}
};
}
- (void)setProductionChapterModel:(TFProductionChapterModel *)productionChapterModel
{
[super setProductionChapterModel:productionChapterModel];
WS(weakSelf)
[[WXYZ_AudioSettingHelper sharedManager] getCurrentTimingBlock:^(NSUInteger currentTime) {
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.timingButton.buttonTitle = [NSString stringWithFormat:@"%02zd:%02zd", (NSInteger)(currentTime / 60), (NSInteger)(currentTime % 60)];
});
} finishBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == 1) {
weakSelf.timingButton.buttonTitle = TFLocalizedString(@"听完本章节");
} else if ([[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == 0) {
weakSelf.timingButton.buttonTitle = TFLocalizedString(@"定时");
} else {
weakSelf.timingButton.buttonTitle = TFLocalizedString(@"定时");
#if __has_include(<iflyMSC/IFlyMSC.h>)
if (weakSelf.playerState == TFBasicVoicePlayerStatePlaying) {
[[IFlySpeechSynthesizer sharedInstance] pauseSpeaking];
}
#endif
}
});
}];
if (productionChapterModel.chapter_id == 0) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"章节正在更新中")];
});
self.playerState = TFBasicVoicePlayerStateStoped;
return;
}
if (self.temp_chapterModel.chapter_id == productionChapterModel.chapter_id && self.temp_chapterModel.is_preview == productionChapterModel.is_preview && ![TFUserInfoManager shareInstance].auto_sub) {
if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying && ![[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio]) {
[[IFlySpeechSynthesizer sharedInstance] resumeSpeaking];
[[WXYZ_Player sharedPlayer] pause];
}
return;
}
if ([[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio]) {
[[WXYZ_AudioSettingHelper sharedManager] playPageViewShow:NO productionType:TFProductionTypeAudio];
if ([TFAudioPlayViewController sharedManager].speaking) {
self.playerState = TFBasicVoicePlayerStateStoped;
}
return;
}
self.temp_chapterModel = [productionChapterModel modelCopy];
if (productionChapterModel.is_preview && ![TFUserInfoManager shareInstance].auto_sub) {
self.playerState = TFBasicVoicePlayerStateStoped;
[self.iFlySpeechSynthesizer stopSpeaking];
[self showPayView];
return;
}
[self initIFlySpeech];
}
- (void)initIFlySpeech
{
//设置在线工作方式
[self.iFlySpeechSynthesizer setParameter:[IFlySpeechConstant TYPE_CLOUD]
forKey:[IFlySpeechConstant ENGINE_TYPE]];
[self.iFlySpeechSynthesizer setParameter:@"wxyz.pcm"
forKey: [IFlySpeechConstant TTS_AUDIO_PATH]];
// 语速
WXYZ_AudioSettingHelper *audioTool = [WXYZ_AudioSettingHelper sharedManager];
[self.iFlySpeechSynthesizer setParameter:[TFUtilsHelper formatStringWithInteger:[[[audioTool getReadSpeedValuesWithProducitionType:self.productionType] objectAtIndex:[audioTool getReadSpeedWithProducitionType:self.productionType]] floatValue] * 50] forKey:[IFlySpeechConstant SPEED]];
//设置音量,取值范围 0~100
[self.iFlySpeechSynthesizer setParameter:@"1" forKey:[IFlySpeechConstant MPPLAYINGINFOCENTER]];
// 音量
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[self.iFlySpeechSynthesizer setParameter:[TFUtilsHelper formatStringWithInteger:audioSession.outputVolume * 100] forKey: [IFlySpeechConstant VOLUME]];
// 发音人
[self.iFlySpeechSynthesizer setParameter:[[audioTool getReadVoiceValuesWithProducitionType:self.productionType] objectAtIndex:[audioTool getReadVoiceWithProducitionType:self.productionType]] forKey:[IFlySpeechConstant VOICE_NAME]];
WS(weakSelf)
[[TFReaderBookManager sharedManager] getChapterTextWithBook_id:self.productionChapterModel.production_id chapter_index:[self.productionChapterModel.display_order integerValue] completionHandler:^(NSString *content) {
[weakSelf.segmentCharacterArray removeAllObjects];
content = [content stringByReplacingOccurrencesOfString:@"W$$X" withString:@""];
content = [content stringByReplacingOccurrencesOfString:k_Chapter_RequstFail withString:@""];
// 分割长度
NSInteger segmentLength = 3500;
// 分割数量
NSInteger segmentCount = content.length / segmentLength + (content.length % segmentLength > 0 ? 1 : 0);
// 整数量分割
if (segmentCount == 1) {
[weakSelf.segmentCharacterArray addObject:content];
} else {
for (int i = 0; i < segmentCount; i ++) {
if (segmentCount - 1 == i) {
[weakSelf.segmentCharacterArray addObject:[content substringWithRange:NSMakeRange(i * segmentLength, content.length % segmentLength)]];
} else {
[weakSelf.segmentCharacterArray addObject:[content substringWithRange:NSMakeRange(i * segmentLength, segmentLength)]];
}
}
}
if (weakSelf.segmentCharacterArray.count > 0) {
[weakSelf.iFlySpeechSynthesizer startSpeaking:[weakSelf.segmentCharacterArray firstObject]];
}
[[WXYZ_PlayingInfoCenter sharedManager] showPlayingInfoCenterWithProductionChapterModel:weakSelf.productionChapterModel];
}];
}
#pragma mark - WXYZ_PlayingInfoCenterDelegate
- (void)playRemoteCommand
{
if ([WXYZ_TouchAssistantView sharedManager].productionType == TFProductionTypeNovel) {
if (self.playerState == TFBasicVoicePlayerStatePause) {
[self.iFlySpeechSynthesizer resumeSpeaking];
}
}
}
- (void)pauseRemoteCommand
{
if ([WXYZ_TouchAssistantView sharedManager].productionType == TFProductionTypeNovel) {
if (self.playerState == TFBasicVoicePlayerStatePlaying) {
[self.iFlySpeechSynthesizer pauseSpeaking];
}
}
}
- (void)lastRemoteCommand
{
if ([WXYZ_TouchAssistantView sharedManager].productionType == TFProductionTypeNovel) {
[self skipToLastChapter];
}
}
- (void)nextRemoteCommand
{
if ([WXYZ_TouchAssistantView sharedManager].productionType == TFProductionTypeNovel) {
[self skipToNextChapter];
}
}
#pragma mark - IFlySpeechDelegate
- (void)onCompleted:(IFlySpeechError *)error
{
if (error) {
if ([TFNetworkManager networkingStatus] == NO) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"当前为离线状态,只可查看缓存内容哦")];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"播放出错")];
}
self.playerState = TFBasicVoicePlayerStateStoped;
}
}
// 合成开始
- (void)onSpeakBegin
{
self.playerState = TFBasicVoicePlayerStatePlaying;
if ([[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio] && [[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeNovel] && [WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying) {
[self.iFlySpeechSynthesizer pauseSpeaking];
} else {
if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying) {
[[WXYZ_Player sharedPlayer] pause];
}
}
[[WXYZ_PlayingInfoCenter sharedManager] showPlayingInfoCenterWithProductionChapterModel:self.productionChapterModel];
}
// 合成播放进度
- (void)onSpeakProgress:(int)progress beginPos:(int)beginPos endPos:(int)endPos
{
if (progress == 100) { // 片段播放结束
[self.segmentCharacterArray removeFirstObject];
if (self.segmentCharacterArray.count == 0) {
if ([[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == 1) {
[[WXYZ_AudioSettingHelper sharedManager] setReadTimingWithIndex:0];
self.timingButton.buttonTitle = TFLocalizedString(@"定时");
[self.iFlySpeechSynthesizer pauseSpeaking];
self.playerState = TFBasicVoicePlayerStatePause;
} else {
if (self.productionChapterModel.next_chapter > 0 && self.productionChapterModel.next_chapter) {
[self skipToNextChapter];
}
}
} else {
[self.iFlySpeechSynthesizer startSpeaking:[self.segmentCharacterArray firstObject]];
}
}
}
// 暂停播放回调
- (void)onSpeakPaused
{
self.playerState = TFBasicVoicePlayerStatePause;
[[WXYZ_PlayingInfoCenter sharedManager] hiddenPlayingInfoCenter];
}
// 恢复播放回调
- (void)onSpeakResumed
{
self.playerState = TFBasicVoicePlayerStatePlaying;
[[WXYZ_PlayingInfoCenter sharedManager] showPlayingInfoCenterWithProductionChapterModel:self.productionChapterModel];
}
// 取消播放
- (void)onSpeakCancel
{
self.playerState = TFBasicVoicePlayerStateStoped;
[[WXYZ_PlayingInfoCenter sharedManager] hiddenPlayingInfoCenter];
}
- (void)relationViewTitleChange
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self setRelationViewTitle:[[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAudio] getReadingRecordChapterTitleWithProduction_id:self.relationModel.production_id]?:self.relationModel.chapter_title?:@""];
});
}
#pragma mark - lazy
- (IFlySpeechSynthesizer *)iFlySpeechSynthesizer
{
if (!_iFlySpeechSynthesizer) {
_iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
//设置协议委托对象
_iFlySpeechSynthesizer.delegate = self;
}
return _iFlySpeechSynthesizer;
}
- (NSMutableArray *)segmentCharacterArray
{
if (!_segmentCharacterArray) {
_segmentCharacterArray = [NSMutableArray array];
}
return _segmentCharacterArray;
}
#endif
@end
@@ -0,0 +1,28 @@
//
// WXYZ_BookAiPlayPageViewController.h
// WXReader
//
// Created by Andrew on 2020/3/8.
// Copyright © 2020 Andrew. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_BookAiPlayPageViewController : TFBasicViewController
@property (nonatomic, assign, readonly) BOOL speaking;
@property (nonatomic, assign, readonly) BOOL stoped; // 暂停不可播放状态
@property (nonatomic, strong) TFProductionModel *bookModel;
interface_singleton
- (instancetype)init NS_UNAVAILABLE;
- (void)loadDataWithBookModel:(TFProductionModel * __nullable)bookModel chapterModel:(TFProductionChapterModel * __nullable)chapterModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,850 @@
//
// WXYZ_BookAiPlayPageViewController.m
// WXReader
//
// Created by Andrew on 2020/3/8.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookAiPlayPageViewController.h"
#import "TFCommentsViewController.h"
#import "TFReadNovelViewController.h"
#import "TFAudioPlayViewController.h"
#import "WXYZ_BookAiPlayPageHeaderView.h"
#import "TFBookStoreNovelStyleOneCell.h"
#import "TFCommentsViewCell.h"
#import "TFPublicAdvertisementViewCell.h"
#import "CXTextView.h"
#import "CXCustomTextView.h"
#import "WXYZ_TouchAssistantView.h"
#import "WXYZ_PlayPageModel.h"
#import "WXYZ_Player.h"
#import "WXYZ_AudioSettingHelper.h"
#import "TFShareManager.h"
#import "TFKeyboardManager.h"
#import "TFCollectionManager.h"
#import "TFReadRecordManager.h"
@interface WXYZ_BookAiPlayPageViewController () <UITableViewDelegate, UITableViewDataSource>
{
CXTextView *commentTextView;
TFKeyboardManager *keyboardManager;
}
@property (nonatomic, strong) TFProductionChapterModel *chapterModel;
@property (nonatomic, strong) WXYZ_PlayPageModel *audioPlayPageModel;
@property (nonatomic, strong) WXYZ_BookAiPlayPageHeaderView *headerView;
@property (nonatomic, strong) UIButton *addBookRack;
@property (nonatomic, strong) UIView *bottomMenu;
@property (nonatomic, strong) UIView *sectionHeaderView;
@property (nonatomic, strong) UILabel *sectionTitleLabel;
@property (nonatomic, strong) UIButton *sectionBottomCommentButton;
@property (nonatomic, strong) UILabel *commentConnerLabel;
@property (nonatomic, assign) BOOL needRefresh;
@end
@implementation WXYZ_BookAiPlayPageViewController
implementation_singleton(WXYZ_BookAiPlayPageViewController)
- (instancetype)init
{
if (self = [super init]) {
[self initialize];
[self createSubviews];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self hiddenNavigationBar:YES];
}
- (void)loadDataWithBookModel:(TFProductionModel *)bookModel chapterModel:(TFProductionChapterModel *)chapterModel
{
[[TFCollectionManager shareManagerWithProductionType:TFProductionTypeAudio] moveCollectionToTopWithProductionModel:bookModel];
if (self.bookModel.production_id == bookModel.production_id && self.chapterModel.chapter_id == chapterModel.chapter_id) {
chapterModel.production_id = self.bookModel.production_id;
chapterModel.name = self.bookModel.name;
chapterModel.cover = self.bookModel.cover;
return;
}
if (bookModel) {
self.bookModel = bookModel;
}
if (!chapterModel) {
NSInteger recordChapter_id = [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] getReadingRecordChapter_idWithProduction_id:self.bookModel.production_id];
if (recordChapter_id == 0) {
if (self.bookModel.chapter_list.count > 0) {
chapterModel = [self.bookModel.chapter_list firstObject];
} else {
chapterModel = [[TFProductionChapterModel alloc] init];
}
} else {
for (TFProductionChapterModel *t_model in self.bookModel.chapter_list) {
if (t_model.chapter_id == recordChapter_id) {
chapterModel = t_model;
break;
}
}
}
}
chapterModel.production_id = self.bookModel.production_id;
chapterModel.name = self.bookModel.name;
chapterModel.cover = self.bookModel.cover;
self.chapterModel = chapterModel;
[[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] addReadingRecordWithProduction_id:chapterModel.production_id chapter_id:chapterModel.chapter_id chapterTitle:chapterModel.chapter_title];
self.headerView.productionChapterModel = chapterModel;
self.headerView.chapter_list = self.bookModel.chapter_list;
[self.mainTableViewGroup setTableHeaderView:self.headerView];
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[self.addBookRack setTitle:TFLocalizedString(@"已加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kGrayTextColor forState:UIControlStateNormal];
self.addBookRack.enabled = NO;
} else {
[self.addBookRack setTitle:TFLocalizedString(@"加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
self.addBookRack.enabled = YES;
}
[self netRequest];
}
- (void)initialize
{
self.needRefresh = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeAiChapter:) name:Notification_Change_AiBook_Chapter object:nil];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setStatusBarDefaultStyle];
[[WXYZ_AudioSettingHelper sharedManager] playPageViewShow:YES productionType:TFProductionTypeAi];
[[WXYZ_TouchAssistantView sharedManager] hiddenAssistiveTouchView];
[[WXYZ_TouchAssistantView sharedManager] setPlayerProductionType:TFProductionTypeNovel];
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[self.addBookRack setTitle:TFLocalizedString(@"已加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kGrayTextColor forState:UIControlStateNormal];
self.addBookRack.enabled = NO;
} else {
[self.addBookRack setTitle:TFLocalizedString(@"加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
self.addBookRack.enabled = YES;
}
}
- (void)viewWillDisappear:(BOOL)animated
{
if (!([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying)) {
[[WXYZ_TouchAssistantView sharedManager] showAssistiveTouchViewWithImageCover:self.bookModel.cover productionType:TFProductionTypeNovel];
} else {
[[WXYZ_TouchAssistantView sharedManager] showAssistiveTouchView];
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[WXYZ_TouchAssistantView sharedManager] hiddenAssistiveTouchView];
}
- (void)createSubviews
{
WS(weakSelf)
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
backButton.frame = CGRectMake(10, PUB_NAVBAR_OFFSET + 20, 44, 44);
backButton.backgroundColor = [UIColor clearColor];
backButton.adjustsImageWhenHighlighted = NO;
[backButton.titleLabel setFont:kMainFont];
[backButton setTitleColor:kBlackColor forState:UIControlStateNormal];
[backButton setImage:[[UIImage imageNamed:@"public_down_arrow"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[backButton setImageEdgeInsets:UIEdgeInsetsMake(12, 12, 12, 12)];
[backButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[backButton setTintColor:kBlackColor];
[backButton addTarget:self action:@selector(popViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
self.addBookRack = [UIButton buttonWithType:UIButtonTypeCustom];
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[self.addBookRack setTitle:TFLocalizedString(@"已加入书架") forState:UIControlStateNormal];
[self.addBookRack setTitleColor:kGrayTextColor forState:UIControlStateNormal];
self.addBookRack.enabled = NO;
} else {
[self.addBookRack setTitle:TFLocalizedString(@"加入书架") forState:UIControlStateNormal];
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
self.addBookRack.enabled = YES;
}
self.addBookRack.backgroundColor = kWhiteColor;
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
[self.addBookRack.titleLabel setFont:kMainFont];
[self.addBookRack setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight];
[self.addBookRack addTarget:self action:@selector(addBookRackClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.addBookRack];
[self.addBookRack mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.view.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(backButton.mas_centerY);
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
make.height.mas_equalTo(44);
}];
self.mainTableViewGroup.delegate = self;
self.mainTableViewGroup.dataSource = self;
[self.view addSubview:self.mainTableViewGroup];
[self.mainTableViewGroup mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(PUB_NAVBAR_HEIGHT);
make.width.mas_equalTo(self.view.mas_width);
make.height.mas_equalTo(self.view.mas_height).with.offset(- PUB_TABBAR_HEIGHT- PUB_NAVBAR_HEIGHT);
}];
[self.mainTableViewGroup setTableHeaderView:self.headerView];
self.bottomMenu = [[UIView alloc] init];
self.bottomMenu.backgroundColor = [UIColor whiteColor];
self.bottomMenu.layer.shadowColor = kBlackColor.CGColor;
self.bottomMenu.layer.shadowOpacity = 0.1;
self.bottomMenu.layer.shadowRadius = 1;
self.bottomMenu.layer.shadowOffset = CGSizeMake(0, - 1);
[self.view addSubview:self.bottomMenu];
[self.bottomMenu mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.view.mas_left);
make.bottom.mas_equalTo(self.view.mas_bottom).with.offset(- PUB_TABBAR_OFFSET);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET);
}];
TFButton *shareButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"分享") buttonImageName:@"public_share" buttonIndicator:TFButtonIndicatorTitleBottom];
shareButton.tag = 0;
shareButton.graphicDistance = 5;
shareButton.buttonImageScale = 0.4;
shareButton.buttonTintColor = kBlackColor;
shareButton.buttonTitleColor = kGrayTextLightColor;
[shareButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.bottomMenu addSubview:shareButton];
[shareButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.bottomMenu.mas_right).with.offset(- kHalfMargin);
make.top.mas_equalTo(self.bottomMenu.mas_top).with.offset(5);
make.width.height.mas_equalTo(40);
}];
TFButton *commentButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"听书评论") buttonImageName:@"audio_comment" buttonIndicator:TFButtonIndicatorTitleBottom];
commentButton.tag = 1;
commentButton.graphicDistance = 5;
commentButton.buttonImageScale = 0.45;
commentButton.buttonTitleColor = kGrayTextLightColor;
[commentButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.bottomMenu addSubview:commentButton];
[commentButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(shareButton.mas_left).with.offset(- kHalfMargin);
make.centerY.mas_equalTo(shareButton.mas_centerY);
make.width.height.mas_equalTo(shareButton);
}];
self.commentConnerLabel = [[UILabel alloc] init];
self.commentConnerLabel.text = @"0";
self.commentConnerLabel.textAlignment = NSTextAlignmentCenter;
self.commentConnerLabel.textColor = kMainColor;
self.commentConnerLabel.backgroundColor = [UIColor whiteColor];
self.commentConnerLabel.font = [UIFont systemFontOfSize:6];
[commentButton addSubview:self.commentConnerLabel];
[self.commentConnerLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(commentButton.mas_centerX).with.offset(1);
make.right.mas_equalTo(commentButton.mas_right).with.offset(- 5);
make.top.mas_equalTo(commentButton.mas_top).with.offset(- 1);
make.height.mas_equalTo(6);
}];
UIView *commentBottomView = [[UIView alloc] init];
commentBottomView.backgroundColor = kGrayViewColor;
commentBottomView.layer.cornerRadius = 20;
[self.bottomMenu addSubview:commentBottomView];
[commentBottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.bottomMenu.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(self.bottomMenu.mas_top).with.offset(5);
make.right.mas_equalTo(commentButton.mas_left).with.offset(- kHalfMargin);
make.height.mas_equalTo(40);
}];
UIImageView *leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"audio_pencil"]];
[commentBottomView addSubview:leftView];
[leftView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMoreHalfMargin);
make.top.mas_equalTo(commentBottomView.mas_top).with.offset(10);
make.height.width.mas_equalTo(16);
}];
commentTextView = [[CXTextView alloc] initWithFrame:CGRectMake(kMoreHalfMargin + 16 + kHalfMargin, 0, SCREEN_WIDTH - (kMoreHalfMargin + 16 + kHalfMargin + kHalfMargin + 3 * 40 + 5 * kHalfMargin), 40)];
commentTextView.placeholder = TFLocalizedString(@"我来说两句...");
commentTextView.maxLine = 5;
commentTextView.maxLength = 200;
commentTextView.v_margin = 10;
commentTextView.font = kMainFont;
commentTextView.backgroundColor = [UIColor clearColor];
commentTextView.layer.cornerRadius = 15;
commentTextView.textView.backgroundColor = [UIColor clearColor];
commentTextView.textHeightChangeBlock = ^(CGFloat height) {
[commentBottomView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(height);
}];
[weakSelf.bottomMenu mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(10 + height);
}];
[weakSelf.mainTableViewGroup mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(weakSelf.view.mas_height).with.offset(- PUB_TABBAR_OFFSET - PUB_NAVBAR_HEIGHT - height - 10);
}];
};
commentTextView.returnHandlerBlock = ^{
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
[weakSelf sendCommentNetRequest];
};
[commentBottomView addSubview:commentTextView];
keyboardManager = [[TFKeyboardManager alloc] initObserverWithAdaptiveMovementView:commentBottomView];
keyboardManager.keyboardHeightChanged = ^(CGFloat keyboardHeight, CGFloat shouldMoveDistance, CGRect shouldMoveFrame) {
[weakSelf.bottomMenu mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(weakSelf.view.mas_bottom).with.offset(keyboardHeight == 0 ? - PUB_TABBAR_OFFSET:- keyboardHeight);
}];
};
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[TFKeyboardManager hideKeyboard];
}
#pragma mark - UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case 0:
if (self.audioPlayPageModel.advert.ad_type != 0) {
return 1;
}
break;
case 1:
if (self.audioPlayPageModel.list.count > 0) {
return 1;
}
break;
case 2:
return self.audioPlayPageModel.comment.list.count;
break;
default:
break;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case 0:
return [self createAdCellWithTableView:tableView indexPath:indexPath];
break;
case 1:
return [self createSingleStyleCellWithTableView:tableView indexPath:indexPath listArray:self.audioPlayPageModel.list];
break;
case 2:
return [self createCommentCellWithTableView:tableView indexPath:indexPath labelModel:[self.audioPlayPageModel.comment.list objectOrNilAtIndex:indexPath.row]];
break;
default:
break;
}
return [[UITableViewCell alloc] init];
}
- (UITableViewCell *)createSingleStyleCellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath listArray:(NSArray *)listArray
{
WS(weakSelf)
static NSString *cellName = @"TFBookStoreNovelStyleOneCell";
TFBookStoreLabelModel *labelModel = [[TFBookStoreLabelModel alloc] init];
labelModel.list = listArray;
labelModel.label = TFLocalizedString(@"猜你喜欢");
TFBookStoreNovelStyleOneCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[TFBookStoreNovelStyleOneCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.labelModel = labelModel;
cell.cellDidSelectItemBlock = ^(NSInteger production_id) {
TFNovelDetailViewController *vc = [[TFNovelDetailViewController alloc] init];
vc.book_id = production_id;
[weakSelf.navigationController pushViewController:vc animated:YES];
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (UITableViewCell *)createCommentCellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath labelModel:(TFCommentsListModel *)commentModel
{
static NSString *cellName = @"TFCommentsViewCell";
TFCommentsViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[TFCommentsViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.commentModel = commentModel;
[cell setIsPreview:YES lastRow:(self.audioPlayPageModel.comment.list.count - 1 == indexPath.row)];
cell.hiddenEndLine = NO;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (UITableViewCell *)createAdCellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath
{
static NSString *cellName = @"TFPublicAdvertisementViewCell";
TFPublicAdvertisementViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[TFPublicAdvertisementViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
[cell setAdModel:self.audioPlayPageModel.advert refresh:self.needRefresh];
cell.mainTableView = tableView;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
//section头部间距
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
#if TF_Comments_Mode
if (!self.bookModel) {
return CGFLOAT_MIN;
}
if (section == 2) {// 评论头部高度
return 54;
}
#endif
return kQuarterMargin;
}
//section头部视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 2) {
UIView *sectionView = self.sectionHeaderView;
self.sectionTitleLabel.text = [NSString stringWithFormat:@"%@ (%@)", TFLocalizedString(@"本章评论"),[TFUtilsHelper formatStringWithInteger:self.audioPlayPageModel.comment_total_count]];
return sectionView;
}
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, kHalfMargin)];
view.backgroundColor = kGrayViewColor;
return view;
}
- (UIView *)sectionHeaderView
{
if (!_sectionHeaderView) {
_sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 54)];
_sectionHeaderView.backgroundColor = [UIColor whiteColor];
UIView *grayLine = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 10)];
grayLine.backgroundColor = kGrayViewColor;
[_sectionHeaderView addSubview:grayLine];
UIImageView *mainTitleHoldView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"book_label_hold"]];
[_sectionHeaderView addSubview:mainTitleHoldView];
[mainTitleHoldView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kHalfMargin);
make.centerY.mas_equalTo(_sectionHeaderView.mas_centerY).with.offset(5);
make.width.height.mas_equalTo(kHalfMargin + kQuarterMargin);
}];
[_sectionHeaderView addSubview:self.sectionTitleLabel];
}
return _sectionHeaderView;
}
- (UILabel *)sectionTitleLabel
{
if (!_sectionTitleLabel) {
_sectionTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(kMargin + kHalfMargin, 10, SCREEN_WIDTH - kMargin, 44)];
_sectionTitleLabel.textAlignment = NSTextAlignmentLeft;
_sectionTitleLabel.textColor = kBlackColor;
_sectionTitleLabel.backgroundColor = [UIColor whiteColor];
_sectionTitleLabel.font = kBoldFont16;
}
return _sectionTitleLabel;
}
//section底部间距
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
#if TF_Comments_Mode
if (!self.bookModel) {
return CGFLOAT_MIN;
}
if (section == 2) {
return 56;
}
#endif
return CGFLOAT_MIN;
}
//section底部视图
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 50)];
view.backgroundColor = kWhiteColor;
if (section == 2) {
if (self.audioPlayPageModel) {
if (self.audioPlayPageModel.comment.list.count == 0) {
[self.sectionBottomCommentButton setTitle:TFLocalizedString(@"暂无评论,点击抢沙发") forState:UIControlStateNormal];
} else {
[self.sectionBottomCommentButton setTitle:[NSString stringWithFormat:@"%@(%@%@)", TFLocalizedString(@"查看全部评论"), [TFUtilsHelper formatStringWithInteger:self.audioPlayPageModel.comment_total_count], TFLocalizedString(@"")] forState:UIControlStateNormal];
}
[view addSubview:self.sectionBottomCommentButton];
}
}
return view;
}
- (void)changeAiChapter:(NSNotification *)noti
{
NSInteger chapter_id = [[TFUtilsHelper formatStringWithObject:noti.object] integerValue];
// 支付成功的章节更新预览内容
NSArray *success_chapter_ids = [noti.userInfo objectForKey:@"success_chapter_ids"];
if (success_chapter_ids.count > 0) {
for (NSString *chapter_id in success_chapter_ids) {
for (TFProductionChapterModel *t_model in self.bookModel.chapter_list) {
if (t_model.chapter_id == [chapter_id integerValue]) {
t_model.is_preview = 0;
break;
}
}
}
}
for (TFProductionChapterModel *t_model in self.bookModel.chapter_list) {
if (t_model.chapter_id == chapter_id) {
t_model.name = self.chapterModel.name;
t_model.cover = self.chapterModel.cover;
t_model.production_id = self.chapterModel.production_id;
self.headerView.productionChapterModel = t_model;
[[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] addReadingRecordWithProduction_id:self.bookModel.production_id chapter_id:chapter_id chapterTitle:t_model.chapter_title];
break;
}
}
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[self.addBookRack setTitle:TFLocalizedString(@"已加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kGrayTextColor forState:UIControlStateNormal];
self.addBookRack.enabled = NO;
} else {
[self.addBookRack setTitle:TFLocalizedString(@"加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
self.addBookRack.enabled = YES;
}
[self requestChapterCommentWithChapter_id:chapter_id];
}
- (BOOL)speaking
{
if (self.headerView.playerState == TFBasicVoicePlayerStatePlaying) {
return YES;
}
return NO;
}
- (BOOL)stoped
{
if (self.headerView.playerState == TFBasicVoicePlayerStateStoped) {
return YES;
}
return NO;
}
- (UIButton *)sectionBottomCommentButton
{
if (!_sectionBottomCommentButton) {
_sectionBottomCommentButton = [UIButton buttonWithType:UIButtonTypeCustom];
_sectionBottomCommentButton.frame = CGRectMake(SCREEN_WIDTH / 4, kHalfMargin, SCREEN_WIDTH / 2 + kMargin, 36);
_sectionBottomCommentButton.backgroundColor = [UIColor whiteColor];
_sectionBottomCommentButton.layer.cornerRadius = 18;
_sectionBottomCommentButton.layer.borderColor = kMainColor.CGColor;
_sectionBottomCommentButton.layer.borderWidth = 0.4f;
[_sectionBottomCommentButton setTitleColor:kMainColor forState:UIControlStateNormal];
[_sectionBottomCommentButton.titleLabel setFont:kFont12];
[_sectionBottomCommentButton addTarget:self action:@selector(commentClick) forControlEvents:UIControlEventTouchUpInside];
}
return _sectionBottomCommentButton;
}
- (WXYZ_BookAiPlayPageHeaderView *)headerView
{
if (!_headerView) {
WS(weakSelf)
_headerView = [[WXYZ_BookAiPlayPageHeaderView alloc] initWithProductionType:TFProductionTypeAi];
_headerView.checkOriginalBlock = ^(TFProductionChapterModel * _Nonnull chapterModel) {
if (weakSelf.navigationController.view.tag == 2345) {
[weakSelf popViewController];
return;
}
TFReadNovelViewController *vc = [[TFReadNovelViewController alloc] init];
vc.book_id = weakSelf.bookModel.production_id;
vc.bookModel = weakSelf.bookModel;
[weakSelf.navigationController pushViewController:vc animated:YES];
};
_headerView.checkRelationProductionBlock = ^(WXYZ_RelationModel * _Nonnull relationModel) {
dispatch_async(dispatch_get_main_queue(), ^{
[[TFCollectionManager shareManagerWithProductionType:TFProductionTypeAudio] moveCollectionToTopWithProductionModel:weakSelf.bookModel];
TFAudioPlayViewController *vc = [TFAudioPlayViewController sharedManager];
[vc loadDataWithAudio_id:relationModel.production_id chapter_id:relationModel.chapter_id];
if (!vc.presentedViewController) {
TFNavigationController *nav = [[TFNavigationController alloc] initWithRootViewController:vc];
[[TFViewHelper getWindowRootController] presentViewController:nav animated:YES completion:nil];
} else {
[weakSelf popViewController];
if ([weakSelf.navigationController.viewControllers.lastObject isKindOfClass:WXYZ_BookAiPlayPageViewController.class]) {
[kNotification postNotificationName:NSNotification_Reader_Back object:@"1"];
}
}
});
};
}
return _headerView;
}
#pragma mark - 点击事件
- (void)addBookRackClick
{
[[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] addCollectionWithProductionModel:self.bookModel];
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"已加入书架")];
[self.addBookRack setTitle:TFLocalizedString(@"已加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kGrayTextColor forState:UIControlStateNormal];
self.addBookRack.enabled = NO;
} else {
[self.addBookRack setTitle:TFLocalizedString(@"加入书架") forState:UIControlStateNormal];
[self.addBookRack mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(self.addBookRack.intrinsicContentSize.width);
}];
[self.addBookRack setTitleColor:kBlackColor forState:UIControlStateNormal];
self.addBookRack.enabled = YES;
}
[TFUtilsHelper synchronizationRackProductionWithProduction_id:self.bookModel.production_id productionType:TFProductionTypeNovel complete:nil];
}
- (void)commentClick
{
WS(weakSelf)
TFCommentsViewController *vc = [[TFCommentsViewController alloc] init];
vc.production_id = self.bookModel.production_id;
vc.chapter_id = [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] getReadingRecordChapter_idWithProduction_id:self.bookModel.production_id];
vc.productionType = TFProductionTypeNovel;
vc.commentsSuccessBlock = ^(TFCommentsListModel *commentModel) {
TFProductionModel *t_model = weakSelf.bookModel;
// 评论数++
t_model.total_comment ++;
// 评论数组model添加
NSMutableArray *t_array = [NSMutableArray arrayWithArray:weakSelf.audioPlayPageModel.comment.list];
[t_array insertObject:commentModel atIndex:0];
weakSelf.audioPlayPageModel.comment.list = [t_array copy];
weakSelf.bookModel = t_model;
[weakSelf.mainTableViewGroup reloadData];
weakSelf.commentConnerLabel.text = [NSString stringWithFormat:@"%@", weakSelf.audioPlayPageModel.comment_total_count > 99?@"99+":[TFUtilsHelper formatStringWithInteger:weakSelf.audioPlayPageModel.comment_total_count]];
};
[self.navigationController pushViewController:vc animated:YES];
}
- (void)toolBarButtonClick:(TFButton *)sender
{
if (sender.tag == 0) { // 分享
[TFShareManager shareWithProduction_id:NSStringFromInteger(self.bookModel.production_id) chapter_id:nil type:TFShareTypeAudio];
}
if (sender.tag == 1) {
[self commentClick];
}
}
- (void)netRequest
{
WS(weakSelf)
NSInteger chapter_id = [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeAi] getReadingRecordChapter_idWithProduction_id:self.bookModel.production_id];
if (chapter_id == 0) {
TFProductionChapterModel *t_model = [self.bookModel.chapter_list firstObject];
chapter_id = t_model.chapter_id;
}
[TFNetworkTools POST:Ai_Audio_Detail parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:self.bookModel.production_id]?:@"", @"chapter_id":[TFUtilsHelper formatStringWithInteger:chapter_id]} model:WXYZ_PlayPageModel.class success:^(BOOL isSuccess, WXYZ_PlayPageModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.audioPlayPageModel = t_model;
weakSelf.commentConnerLabel.text = [NSString stringWithFormat:@"%@", weakSelf.audioPlayPageModel.comment_total_count > 99?@"99+":[TFUtilsHelper formatStringWithInteger:weakSelf.audioPlayPageModel.comment_total_count]];
weakSelf.headerView.relationModel = weakSelf.audioPlayPageModel.relation;
}
weakSelf.needRefresh = YES;
[weakSelf.mainTableViewGroup reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.needRefresh = NO;
});
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
weakSelf.needRefresh = YES;
[weakSelf.mainTableViewGroup reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.needRefresh = NO;
});
}];
}
- (void)requestChapterCommentWithChapter_id:(NSInteger)chapter_id
{
WS(weakSelf)
[TFNetworkTools POST:Book_Comment_List parameters:@{@"page_num":@"1", @"book_id":[TFUtilsHelper formatStringWithInteger:self.bookModel.production_id]?:@"", @"chapter_id":[TFUtilsHelper formatStringWithInteger:chapter_id]} model:TFCommentsModel.class success:^(BOOL isSuccess, TFCommentsModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.audioPlayPageModel.comment.list = t_model.list;
weakSelf.needRefresh = YES;
[weakSelf.mainTableViewGroup reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.needRefresh = NO;
});
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
weakSelf.needRefresh = YES;
[weakSelf.mainTableViewGroup reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.needRefresh = NO;
});
}];
}
- (void)sendCommentNetRequest
{
if (!TFUserInfoManager.isLogin) {
TFAlertView *alert = [[TFAlertView alloc] init];
alert.alertDetailContent = TFLocalizedString(@"登录后才可以进行评论");
alert.confirmTitle = TFLocalizedString(@"去登录");
alert.cancelTitle = TFLocalizedString(@"暂不");
alert.confirmButtonClickBlock = ^{
[TFLoginOptionsViewController presentLoginView:nil];
};
[alert showAlertView];
return;
}
if ([commentTextView.text isEqualToString:@""]) {
return;
}
NSString *t_text = commentTextView.text;
commentTextView.text = @"";
WS(weakSelf)
[TFNetworkTools POST:Book_Comment_Post parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:self.bookModel.production_id]?:@"", @"chapter_id":[TFUtilsHelper formatStringWithInteger:self.chapterModel.chapter_id], @"content":t_text} model:TFCommentsListModel.class success:^(BOOL isSuccess, TFCommentsListModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"评论成功")];
// 评论数组model添加
NSMutableArray *t_array = [NSMutableArray arrayWithArray:weakSelf.audioPlayPageModel.comment.list];
[t_array insertObject:t_model atIndex:0];
weakSelf.audioPlayPageModel.comment.list = [t_array copy];
weakSelf.audioPlayPageModel.comment_total_count++;
[weakSelf.mainTableViewGroup reloadSection:2 withRowAnimation:UITableViewRowAnimationNone];
weakSelf.commentConnerLabel.text = [NSString stringWithFormat:@"%@", weakSelf.audioPlayPageModel.comment_total_count > 99?@"99+":[TFUtilsHelper formatStringWithInteger:weakSelf.audioPlayPageModel.comment_total_count]];
} else if (Compare_Json_isEqualTo(requestModel.code, 315)) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:requestModel.msg];
} else {
commentTextView.text = t_text;
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
@end
@@ -0,0 +1,48 @@
//
// WXYZ_BookAuthorNoteView.h
// WXReader
//
// Created by LL on 2020/6/2.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@class WXYZ_BookAuthorNoteModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_BookAuthorNoteView : UIView
- (instancetype)initWithFrame:(CGRect)frame notoModel:(WXYZ_BookAuthorNoteModel *)noteModel;
@property (nonatomic, assign) CGFloat noteHeight;
@property (nonatomic, assign) CGFloat spacing;
@end
@interface WXYZ_BookAuthorNoteModel : NSObject
/// 作者寄语
@property (nonatomic, copy) NSString *author_note;
/// 评论数
@property (nonatomic, copy) NSString *comment_num;
/// 月票数
@property (nonatomic, copy) NSString *ticket_num;
/// 打赏数
@property (nonatomic, copy) NSString *reward_num;
@property (nonatomic, assign) NSInteger author_id;
@property (nonatomic, copy) NSString *author_name;
@property (nonatomic, copy) NSString *author_avatar;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,306 @@
//
// WXYZ_BookAuthorNoteView.m
// WXReader
//
// Created by LL on 2020/6/2.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookAuthorNoteView.h"
#import "TFReaderSettingHelper.h"
#import "TFReaderBookManager.h"
#import "WXYZ_GiftView.h"
#import "AppDelegate.h"
#import "TFCommentsViewController.h"
@interface WXYZ_BookAuthorNoteView ()
@property (nonatomic, strong) WXYZ_BookAuthorNoteModel *noteModel;
@property (nonatomic, weak) UIButton *firstBtn;
@property (nonatomic, strong) NSArray<UIButton *> *btnArr;
@property (nonatomic, weak) UIView *mainView;
@property (nonatomic, weak) UIButton *commentBtn;
@property (nonatomic, weak) UIButton *rewardBtn;
@property (nonatomic, weak) UIButton *ticketBtn;
@end
@implementation WXYZ_BookAuthorNoteView
- (instancetype)initWithFrame:(CGRect)frame notoModel:(WXYZ_BookAuthorNoteModel *)noteModel {
if (self = [super initWithFrame:frame]) {
self.noteModel = noteModel;
[self netRequest];
[self initialize];
[self createSubviews];
}
return self;
}
- (void)initialize {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeComment:) name:@"changeComment" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rewardEvent:) name:@"changeReward" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ticketEvent:) name:@"changeTicket" object:nil];
}
- (void)netRequest {
NSDictionary *params = @{
@"book_id" : @([TFReaderBookManager sharedManager].book_id),
@"chapter_id" : @([TFReaderBookManager sharedManager].chapter_id),
@"scroll_type" : @"1",
};
WS(weakSelf)
[TFNetworkTools POST:Book_New_Catalog parameters:params model:TFCatalogModel.class success:^(BOOL isSuccess, TFCatalogModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
weakSelf.noteModel.reward_num = [NSString stringWithFormat:@"%zd", t_model.list.firstObject.reward_num];
weakSelf.noteModel.ticket_num = [NSString stringWithFormat:@"%zd", t_model.list.firstObject.ticket_num];
weakSelf.noteModel.comment_num = [NSString stringWithFormat:@"%zd", t_model.list.firstObject.comment_num];
[weakSelf.rewardBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"打赏") : @"reward_num"}] forState:UIControlStateNormal];
[weakSelf.ticketBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"月票") : @"ticket_num"}] forState:UIControlStateNormal];
[weakSelf.commentBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"评论") : @"comment_num"}] forState:UIControlStateNormal];
} failure:nil];
}
- (void)createSubviews {
self.backgroundColor = [UIColor clearColor];
UIView *mainView = nil;
if (self.noteModel.author_note.length > 0) {
mainView = [[UIView alloc] init];
self.mainView = mainView;
mainView.backgroundColor = [[[TFReaderSettingHelper sharedManager] getReaderTextColor] colorWithAlphaComponent:0.2];
mainView.layer.cornerRadius = 5.0f;
mainView.layer.masksToBounds = YES;
[self addSubview:mainView];
[mainView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self);
make.right.equalTo(self);
make.top.equalTo(self);
}];
UIView *backView = [[UIView alloc] init];
backView.backgroundColor = kColorRGB(83, 59, 37);
[mainView addSubview:backView];
[backView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(mainView);
make.top.equalTo(mainView).offset(11);
make.size.mas_equalTo(CGSizeMake(3.0, 19.0));
}];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.textColor = [[TFReaderSettingHelper sharedManager] getReaderTextColor];
titleLabel.font = kFont14;
titleLabel.text = TFLocalizedString(@"作家的话");
[mainView addSubview:titleLabel];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(backView);
make.left.equalTo(backView.mas_right).offset(kHalfMargin);
make.right.equalTo(mainView);
}];
UIImageView *coverImageView = [[UIImageView alloc] init];
[coverImageView setImageWithURL:[NSURL URLWithString:self.noteModel.author_avatar] placeholder:HoldImage];
coverImageView.contentMode = UIViewContentModeScaleAspectFill;
coverImageView.clipsToBounds = YES;
coverImageView.layer.cornerRadius = 12.0;
coverImageView.layer.masksToBounds = YES;
[mainView addSubview:coverImageView];
[coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(titleLabel);
make.top.equalTo(titleLabel.mas_bottom).offset(14.0);
make.size.mas_equalTo(CGSizeMake(24.0, 24.0));
}];
UILabel *authorLabel = [[UILabel alloc] init];
authorLabel.textColor = [[TFReaderSettingHelper sharedManager] getReaderTextColor];
authorLabel.font = kFont14;
authorLabel.text = self.noteModel.author_name;
[mainView addSubview:authorLabel];
[authorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(coverImageView);
make.left.equalTo(coverImageView.mas_right).offset(kHalfMargin);
make.right.equalTo(mainView);
}];
UILabel *descLabel = [[UILabel alloc] init];
descLabel.textColor = [[TFReaderSettingHelper sharedManager] getReaderTextColor];
descLabel.font = kFont10;
descLabel.numberOfLines = 0;
descLabel.text = self.noteModel.author_note;
[mainView addSubview:descLabel];
[descLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(coverImageView.mas_bottom).offset(11.0);
make.left.equalTo(coverImageView);
make.right.equalTo(mainView).offset(-kHalfMargin);
make.bottom.equalTo(mainView).offset(-kMoreHalfMargin);
}];
}
NSMutableArray<NSDictionary *> *textArr = [NSMutableArray array];
AppDelegate *delegate = (AppDelegate *)kRCodeSync([UIApplication sharedApplication].delegate);
if (self.noteModel.reward_num.length > 0 && delegate.checkSettingModel.system_setting.novel_reward_switch == 1) {
[textArr addObject:@{TFLocalizedString(@"打赏") : @"reward_num"}];
}
if (self.noteModel.ticket_num.length > 0 && delegate.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
[textArr addObject:@{TFLocalizedString(@"月票") : @"ticket_num"}];
}
if (self.noteModel.comment_num.length > 0) {
[textArr addObject:@{TFLocalizedString(@"评论") : @"comment_num"}];
}
if (textArr.count == 0) return;
WS(weakSelf)
NSMutableArray<UIButton *> *btnArr = [NSMutableArray array];
[textArr enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setAttributedTitle:[self atrbuteStringWithDict:obj] forState:UIControlStateNormal];
button.titleLabel.numberOfLines = 0;
if ([obj.allKeys.firstObject isEqualToString:TFLocalizedString(@"评论")]) {
weakSelf.commentBtn = button;
}
if ([obj.allKeys.firstObject isEqualToString:TFLocalizedString(@"打赏")]) {
weakSelf.rewardBtn = button;
}
if ([obj.allKeys.firstObject isEqualToString:TFLocalizedString(@"月票")]) {
weakSelf.ticketBtn = button;
}
button.titleLabel.textAlignment = NSTextAlignmentCenter;
[button addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithActionBlock:^(id _Nonnull sender) {
if ([obj.allValues.firstObject isEqualToString:@"reward_num"]) {
WXYZ_GiftView *mainView = [[WXYZ_GiftView alloc] initWithFrame:CGRectZero bookModel:[TFReaderBookManager sharedManager].bookModel];
mainView.giftNumBlock = ^(NSInteger giftNumber) {
weakSelf.noteModel.reward_num = [TFUtilsHelper formatStringWithInteger:giftNumber];
[button setAttributedTitle:[weakSelf atrbuteStringWithDict:obj] forState:UIControlStateNormal];
};
[mainView show];
} else if ([obj.allValues.firstObject isEqualToString:@"ticket_num"]) {
WXYZ_GiftView *mainView = [[WXYZ_GiftView alloc] initWithFrame:CGRectZero bookModel:[TFReaderBookManager sharedManager].bookModel];
mainView.ticketNumBlock = ^(NSInteger ticketNumber) {
weakSelf.noteModel.ticket_num = [TFUtilsHelper formatStringWithInteger:ticketNumber];
[button setAttributedTitle:[weakSelf atrbuteStringWithDict:obj] forState:UIControlStateNormal];
};
mainView.isTicket = YES;
[mainView show];
} else if ([obj.allValues.firstObject isEqualToString:@"comment_num"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@"TFCommentsViewController"];
}
}]];
[self addSubview:button];
[btnArr addObject:button];
}];
self.btnArr = btnArr;
if (btnArr.count == 1 || btnArr.count == 0) {
if (btnArr.count == 1) {
[btnArr.firstObject mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self);
make.centerX.equalTo(self);
}];
}
} else {
[btnArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:0 leadSpacing:0 tailSpacing:0];
[btnArr mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self);
}];
[btnArr enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (btnArr.count == idx + 1) {
*stop = YES;
}
UIView *splitLine = [[UIView alloc] init];
splitLine.backgroundColor = kColorRGBA(83, 59, 37, 0.8);
splitLine.hidden = btnArr.count == idx + 1;
[obj addSubview:splitLine];
[splitLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(22.0f);
make.width.mas_equalTo(0.5f);
make.right.equalTo(obj);
make.centerY.equalTo(obj);
}];
}];
}
[self setNeedsLayout];
[self layoutIfNeeded];
self.firstBtn = btnArr.firstObject;
}
- (void)changeComment:(NSNotification *)noti {
self.noteModel.comment_num = noti.object;
[self.commentBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"评论") : @"comment_num"}] forState:UIControlStateNormal];
}
- (void)rewardEvent:(NSNotification *)noti {
self.noteModel.reward_num = noti.object;
[self.rewardBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"打赏") : @"reward_num"}] forState:UIControlStateNormal];
}
- (void)ticketEvent:(NSNotification *)noti {
self.noteModel.ticket_num = noti.object;
[self.ticketBtn setAttributedTitle:[self atrbuteStringWithDict:@{TFLocalizedString(@"月票") : @"ticket_num"}] forState:UIControlStateNormal];
}
- (NSAttributedString *)atrbuteStringWithDict:(NSDictionary *)dict {
NSString *text = dict.allKeys.firstObject;
NSString *num = [self.noteModel performSelectorWithArgs:NSSelectorFromString(dict.allValues.firstObject)];
NSMutableAttributedString *atr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n%@", text, num] attributes:@{NSFontAttributeName : kFont10, NSForegroundColorAttributeName : [[TFReaderSettingHelper sharedManager] getReaderTextColor]}];
[atr addAttribute:NSFontAttributeName value:kFont14 range:NSMakeRange(0, text.length)];
return atr;
}
- (void)setSpacing:(CGFloat)spacing {
_spacing = spacing;
if (spacing == -1) {
CGFloat t_spacing = CGRectGetHeight(self.bounds);
t_spacing = t_spacing - self.noteHeight + kHalfMargin;
[self.btnArr mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mainView.mas_bottom).offset(t_spacing);
}];
}
}
- (CGFloat)noteHeight {
CGFloat __block height = 0;
if ([NSThread isMainThread]) {
if (self.mainView) {
height = CGRectGetHeight(self.mainView.bounds) + CGRectGetHeight(self.firstBtn.bounds) + kHalfMargin;
} else {
height = CGRectGetHeight(self.firstBtn.bounds);
}
} else {
dispatch_semaphore_t signal = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_main_queue(), ^{
if (self.mainView) {
height = CGRectGetHeight(self.mainView.bounds) + CGRectGetHeight(self.firstBtn.bounds) + kHalfMargin;
} else {
height = CGRectGetHeight(self.firstBtn.bounds);
}
dispatch_semaphore_signal(signal);
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
}
return height;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
@implementation WXYZ_BookAuthorNoteModel
@end
@@ -0,0 +1,24 @@
//
// WXYZ_BookBackSideHeaderView.h
// WXReader
//
// Created by Andrew on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WXYZ_BookBackSideModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_BookBackSideHeaderView : UIView
@property (nonatomic, copy) void (^commentClickBlock)(void);
@property (nonatomic, strong) WXYZ_BookBackSideModel *headerModel;
@property (nonatomic, strong) TFProductionModel *bookModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,220 @@
//
// WXYZ_BookBackSideHeaderView.m
// WXReader
//
// Created by Andrew on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookBackSideHeaderView.h"
#import "TFShareManager.h"
#import "WXYZ_GiftView.h"
#import "AppDelegate.h"
@implementation WXYZ_BookBackSideHeaderView
{
UILabel *headerTitleLabel;
UILabel *headerDescLabel;
TFButton *commentButton;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self createSubviews];
}
return self;
}
- (void)createSubviews
{
headerTitleLabel = [[UILabel alloc] init];
headerTitleLabel.font = kBoldFont22;
headerTitleLabel.numberOfLines = 0;
headerTitleLabel.textAlignment = NSTextAlignmentLeft;
headerTitleLabel.textColor = kBlackColor;
[self addSubview:headerTitleLabel];
[headerTitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kMargin);
make.width.mas_equalTo(SCREEN_WIDTH - 2 * kMargin);
make.top.mas_equalTo(self.mas_top).with.offset(kMargin);
make.height.mas_equalTo(CGFLOAT_MIN);
}];
headerDescLabel = [[UILabel alloc] init];
headerDescLabel.font = kMainFont;
headerDescLabel.numberOfLines = 0;
headerDescLabel.textAlignment = NSTextAlignmentLeft;
headerDescLabel.textColor = kGrayTextLightColor;
[self addSubview:headerDescLabel];
[headerDescLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(headerTitleLabel.mas_left);
make.right.mas_equalTo(headerTitleLabel.mas_right);
make.top.mas_equalTo(headerTitleLabel.mas_bottom);
make.height.mas_equalTo(CGFLOAT_MIN);
}];
CGFloat buttonWidth = (SCREEN_WIDTH - kMargin) / 3;
AppDelegate *app = (AppDelegate *)kRCodeSync([UIApplication sharedApplication].delegate);
if (app.checkSettingModel.system_setting.novel_reward_switch == 0 && app.checkSettingModel.system_setting.monthly_ticket_switch == 0) {
buttonWidth = (SCREEN_WIDTH - kMargin) / 2;
}
commentButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"评论") buttonImageName:@"book_back_side_comment" buttonIndicator:TFButtonIndicatorTitleBottom];
commentButton.tag = 0;
commentButton.buttonTitleColor = kGrayTextLightColor;
commentButton.graphicDistance = 8;
commentButton.buttonImageScale = 0.4;
[commentButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:commentButton];
[commentButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kHalfMargin);
make.top.mas_equalTo(headerDescLabel.mas_bottom).with.offset(kMargin);
make.width.mas_equalTo(buttonWidth);
make.height.mas_equalTo(50);
}];
{
UIView *line = [[UIView alloc] init];
line.backgroundColor = kColorRGB(204, 204, 204);
[self addSubview:line];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(commentButton.mas_right);
make.centerY.mas_equalTo(commentButton.mas_centerY);
make.width.mas_equalTo(0.8);
make.height.mas_equalTo(commentButton.mas_height).multipliedBy(0.7);
}];
}
TFButton *exceptionalButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"打赏") buttonImageName:@"book_back_side_exceptional" buttonIndicator:TFButtonIndicatorTitleBottom];
exceptionalButton.tag = 1;
exceptionalButton.buttonTitleColor = kGrayTextLightColor;
exceptionalButton.graphicDistance = 8;
exceptionalButton.buttonImageScale = 0.4;
[exceptionalButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:exceptionalButton];
[exceptionalButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(commentButton.mas_right);
make.top.mas_equalTo(commentButton.mas_top);
make.width.mas_equalTo(CGFLOAT_MIN);
make.height.mas_equalTo(commentButton.mas_height);
}];
if (app.checkSettingModel.system_setting.novel_reward_switch == 1 || app.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
[exceptionalButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(commentButton.mas_right);
make.top.mas_equalTo(commentButton.mas_top);
make.width.mas_equalTo(buttonWidth);
make.height.mas_equalTo(commentButton.mas_height);
}];
if (app.checkSettingModel.system_setting.novel_reward_switch == 0 && app.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
exceptionalButton.buttonTitle = TFLocalizedString(@"月票");
}
{
UIView *line = [[UIView alloc] init];
line.backgroundColor = kColorRGB(204, 204, 204);
[self addSubview:line];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(exceptionalButton.mas_right);
make.centerY.mas_equalTo(exceptionalButton.mas_centerY);
make.width.mas_equalTo(0.8);
make.height.mas_equalTo(exceptionalButton.mas_height).multipliedBy(0.7);
}];
}
}
TFButton *shareButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"分享") buttonImageName:@"public_share" buttonIndicator:TFButtonIndicatorTitleBottom];
shareButton.tag = 2;
shareButton.buttonTitleColor = kGrayTextLightColor;
shareButton.graphicDistance = 8;
shareButton.buttonImageScale = 0.35;
[shareButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:shareButton];
[shareButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(exceptionalButton.mas_right);
make.top.mas_equalTo(commentButton.mas_top);
make.width.mas_equalTo(buttonWidth);
make.height.mas_equalTo(commentButton.mas_height);
}];
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, (headerDescLabel.bottom + kHalfMargin + 50 + kMargin));
}
- (void)setHeaderModel:(WXYZ_BookBackSideModel *)headerModel
{
_headerModel = headerModel;
headerTitleLabel.text = headerModel.title?:@"";
[headerTitleLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo([TFViewHelper getDynamicHeightWithLabel:headerTitleLabel]);
}];
headerDescLabel.text = headerModel.desc?:@"";
[headerDescLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo([TFViewHelper getDynamicHeightWithLabel:headerDescLabel]);
}];
if (headerModel.comment_num > 0) {
commentButton.cornerTitle = [TFUtilsHelper formatStringWithInteger:headerModel.comment_num];
if (headerModel.comment_num > 99) {
commentButton.cornerTitle = @"99+";
}
} else {
commentButton.cornerTitle = @"";
}
[self layoutIfNeeded];
}
- (void)setBookModel:(TFProductionModel *)bookModel
{
_bookModel = bookModel;
}
- (void)toolBarButtonClick:(TFButton *)sender
{
switch (sender.tag) {
case 0:
{
if (self.commentClickBlock) {
self.commentClickBlock();
}
}
break;
case 1:
{
WXYZ_GiftView *mainView = [[WXYZ_GiftView alloc] initWithFrame:CGRectZero bookModel:self.bookModel];
[mainView show];
}
break;
case 2:
{
#if TF_FB_Share_Mode
[TFShareManager shareWithProduction_id:[NSString stringWithFormat:@"%zd", self.bookModel.production_id] chapter_id:nil type:TFShareTypeBook];
#endif
}
break;
default:
break;
}
}
@end
@@ -0,0 +1,27 @@
//
// WXYZ_BookBackSideModel.h
// WXReader
//
// Created by Andrew on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFBookStoreLabelModel;
@interface WXYZ_BookBackSideModel : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *desc;
@property (nonatomic, assign) NSInteger comment_num;
@property (nonatomic, strong) TFBookStoreLabelModel *guess_like;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,18 @@
//
// WXYZ_BookBackSideModel.m
// WXReader
//
// Created by Andrew on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookBackSideModel.h"
#import "TFBookStoreLabelModel.h"
@implementation WXYZ_BookBackSideModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{@"guess_like" : [TFBookStoreLabelModel class]};
}
@end
@@ -0,0 +1,19 @@
//
// WXYZ_BookBackSideViewController.h
// WXReader
//
// Created by LL on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
/// 书籍末尾推荐书籍
@interface WXYZ_BookBackSideViewController : TFBasicViewController
@property (nonatomic, strong) TFProductionModel *bookModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,209 @@
//
// WXYZ_BookBackSideViewController.m
// WXReader
//
// Created by LL on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookBackSideViewController.h"
#import "TFCommentsViewController.h"
#import "WXYZ_BookBackSideHeaderView.h"
#import "TFBookStoreNovelStyleOneCell.h"
#import "TFBookStoreNovelStyleTwoCell.h"
#import "TFBookStoreNovelStyleThreeCell.h"
#import "TFBookStoreNovelStyleFourCell.h"
#import "TFPublicAdvertisementViewCell.h"
#import "WXYZ_BookBackSideModel.h"
#import "TFBookStoreLabelModel.h"
@interface WXYZ_BookBackSideViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) WXYZ_BookBackSideModel *backSideModel;
@property (nonatomic, strong) WXYZ_BookBackSideHeaderView *headerView;
@property (nonatomic, assign) BOOL needRefresh;
@end
@implementation WXYZ_BookBackSideViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initialize];
[self createSubviews];
[self netRequest];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Hidden_Tabbar object:@"1"];
[self setStatusBarDefaultStyle];
}
- (void)initialize
{
self.needRefresh = YES;
[self setNavigationBarTitle:self.bookModel.name ?: @""];
self.view.backgroundColor = [UIColor whiteColor];
UIButton *_rightBtn;
[self setNavigationBarRightButton:({
UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_rightBtn = rightBtn;
[rightBtn setImage:[UIImage imageNamed:@"public_home"] forState:UIControlStateNormal];
[rightBtn addTarget:self action:@selector(goHome) forControlEvents:UIControlEventTouchUpInside];
rightBtn;
})];
[_rightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-kMargin);
make.centerY.equalTo(self.navigationBar.navTitleLabel);
}];
}
- (void)createSubviews
{
self.mainTableViewGroup.delegate = self;
self.mainTableViewGroup.dataSource = self;
[self.view addSubview:self.mainTableViewGroup];
[self.mainTableViewGroup mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(PUB_NAVBAR_HEIGHT);
make.width.mas_equalTo(self.view.mas_width);
make.height.mas_equalTo(self.view.mas_height);
}];
WS(weakSelf)
self.mainTableViewGroup.mj_header = [TFRefreshHeader headerWithRefreshingBlock:^{
[weakSelf netRequest];
}];
self.headerView = [[WXYZ_BookBackSideHeaderView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 200)];
self.headerView.commentClickBlock = ^{
TFCommentsViewController *vc = [[TFCommentsViewController alloc] init];
vc.production_id = weakSelf.bookModel.production_id;
vc.commentsSuccessBlock = ^(TFCommentsListModel *commentModel) {
weakSelf.backSideModel.comment_num ++;
weakSelf.headerView.headerModel = weakSelf.backSideModel;
};
[weakSelf.navigationController pushViewController:vc animated:YES];
};
[self.mainTableViewGroup setTableHeaderView:self.headerView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TFBookStoreLabelModel *labelModel = self.backSideModel.guess_like;
if (labelModel.ad_type == 0) {
switch (labelModel.style) {
case 1:
return [self createCellWithTabelView:tableView cellClass:TFBookStoreNovelStyleOneCell.class indexPath:indexPath labelModel:labelModel];
break;
case 2:
return [self createCellWithTabelView:tableView cellClass:TFBookStoreNovelStyleTwoCell.class indexPath:indexPath labelModel:labelModel];
break;
case 3:
return [self createCellWithTabelView:tableView cellClass:TFBookStoreNovelStyleThreeCell.class indexPath:indexPath labelModel:labelModel];
break;
case 4:
return [self createCellWithTabelView:tableView cellClass:TFBookStoreNovelStyleFourCell.class indexPath:indexPath labelModel:labelModel];
break;
default:
return [self createCellWithTabelView:tableView cellClass:TFBookStoreNovelStyleOneCell.class indexPath:indexPath labelModel:labelModel];
break;
}
} else {
return [self createAdStyleCellWithTableView:tableView indexPath:indexPath adModel:labelModel];
}
}
- (UITableViewCell *)createCellWithTabelView:(UITableView *)tableView cellClass:(Class)cellClass indexPath:(NSIndexPath *)indexPath labelModel:(TFBookStoreLabelModel *)labelModel
{
WS(weakSelf)
TFBookStoreNovelBasicViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
if (!cell) {
cell = [[cellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NSStringFromClass(cellClass)];
}
cell.labelModel = labelModel;
cell.cellDidSelectItemBlock = ^(NSInteger production_id) {
TFNovelDetailViewController *vc = [[TFNovelDetailViewController alloc] init];
vc.book_id = production_id;
[weakSelf.navigationController pushViewController:vc animated:YES];
};
cell.index = indexPath;
cell.cellSelectRefreshBlock = ^(TFBookStoreLabelModel *labelModel, NSIndexPath *indexPath) {
[weakSelf refreshRequestWithLabelModel:labelModel indexPath:indexPath];
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (UITableViewCell *)createAdStyleCellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath adModel:(TFBookStoreLabelModel *)labelModel
{
static NSString *cellName = @"TFPublicAdvertisementViewCell";
TFPublicAdvertisementViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[TFPublicAdvertisementViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
[cell setAdModel:labelModel refresh:self.needRefresh];
cell.mainTableView = tableView;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)netRequest
{
WS(weakSelf)
[TFNetworkTools POST:Book_Endof_Recommend parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:self.bookModel.production_id]} model:WXYZ_BookBackSideModel.class success:^(BOOL isSuccess, WXYZ_BookBackSideModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.backSideModel = t_model;
weakSelf.headerView.headerModel = t_model;
weakSelf.needRefresh = YES;
[weakSelf.mainTableViewGroup reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.needRefresh = NO;
});
}
[weakSelf.mainTableViewGroup endRefreshing];
} failure:nil];
}
- (void)refreshRequestWithLabelModel:(TFBookStoreLabelModel *)labelModel indexPath:(NSIndexPath *)indexPath
{
WS(weakSelf)
[TFNetworkTools POST:Book_Guess_Like parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:self.bookModel.production_id]} model:TFBookStoreLabelModel.class success:^(BOOL isSuccess, TFBookStoreLabelModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.backSideModel.guess_like.list = t_model.list;
TFBookStoreNovelBasicViewCell *cell = [weakSelf.mainTableViewGroup cellForRowAtIndexPath:indexPath];
cell.labelModel = t_model;
[cell stopRefreshing];
}
} failure:nil];
}
- (void)goHome
{
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Tabbar_Index object:@"1"];
[self.navigationController popToRootViewControllerAnimated:YES];
}
@end
@@ -0,0 +1,24 @@
//
// WXYZ_BookFrontCoverView.h
// WXReader
//
// Created by LL on 2020/5/23.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TFReaderSettingHelper;
NS_ASSUME_NONNULL_BEGIN
/// 书籍第一章第一页的封面
@interface WXYZ_BookFrontCoverView : UIView
- (instancetype)initWithFrame:(CGRect)frame
bookModel:(TFProductionModel *)bookModel
readerSetting:(TFReaderSettingHelper *)readerSetting;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,133 @@
//
// WXYZ_BookFrontCoverView.m
// WXReader
//
// Created by LL on 2020/5/23.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookFrontCoverView.h"
#import "TFReaderSettingHelper.h"
#import "TFReaderBookManager.h"
@interface WXYZ_BookFrontCoverView ()
@property (nonatomic, strong) TFProductionModel *bookModel;
@property (nonatomic, strong) TFReaderSettingHelper *readerSetting;
@end
@implementation WXYZ_BookFrontCoverView
- (instancetype)initWithFrame:(CGRect)frame
bookModel:(TFProductionModel *)bookModel
readerSetting:(TFReaderSettingHelper *)readerSetting {
if (self = [super initWithFrame:frame]) {
self.bookModel = bookModel;
self.readerSetting = readerSetting;
if ([TFNetworkManager networkingStatus]) {
[self netRquest];
} else {
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
path = [path stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:@"book_catalog"]];
NSString *catalogName = [NSString stringWithFormat:@"%zd_%@", bookModel.production_id, @"catalog"];
NSString *fullPath = [path stringByAppendingFormat:@"/%@.plist", [TFUtilsHelper stringToMD5:catalogName]];
if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:fullPath];
TFCatalogModel *catalog = [TFCatalogModel modelWithDictionary:dict];
if (catalog.author) {
self.bookModel.author = self.bookModel.author ? self.bookModel.author : catalog.author.author_name;
self.bookModel.author_name = self.bookModel.author_name ? self.bookModel.author_name : catalog.author.author_name;
self.bookModel.author_id = self.bookModel.author_id ? self.bookModel.author_id : catalog.author.author_id;
self.bookModel.author_note = self.bookModel.author_note ? self.bookModel.author_note : catalog.author.author_note;
self.bookModel.author_avatar = self.bookModel.author_avatar ? self.bookModel.author_avatar : catalog.author.author_avatar;
} else {
TFProductionModel *t_catalog = [TFProductionModel modelWithDictionary:dict];
self.bookModel.author = self.bookModel.author ? self.bookModel.author : t_catalog.name;
self.bookModel.author_name = self.bookModel.author_name ? self.bookModel.author_name : t_catalog.name;
}
}
[self createSubviews];
}
}
return self;
}
- (void)netRquest {
WS(weakSelf)
[TFNetworkTools POST:Book_New_Catalog parameters:@{@"book_id" : @([TFReaderBookManager sharedManager].book_id)} model:TFCatalogModel.class success:^(BOOL isSuccess, TFCatalogModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
weakSelf.bookModel.author_note = t_model.author.author_note;
weakSelf.bookModel.author = t_model.author.author_name;
weakSelf.bookModel.author_name = t_model.author.author_name;
[weakSelf createSubviews];
} failure:nil];
}
- (void)createSubviews {
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.backgroundColor = [UIColor clearColor];
coverImageView.image = [UIImage imageNamed:@"book_reader_cover"];
[self addSubview:coverImageView];
[coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.text = self.bookModel.name ? : @"";
nameLabel.font = kBoldFont18;
nameLabel.textColor = [self.readerSetting getReaderTitleTextColor];
[coverImageView addSubview:nameLabel];
[nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(coverImageView);
make.bottom.equalTo(coverImageView.mas_centerY);
}];
TFProductionCoverView *bookCoverView = [[TFProductionCoverView alloc] initWithProductionType:TFProductionTypeNovel coverDirection:TFProductionCoverDirectionVertical];
bookCoverView.coverImageUrl = self.bookModel.cover;
[coverImageView addSubview:bookCoverView];
[bookCoverView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(nameLabel.mas_top).offset(-kMargin -kQuarterMargin);
make.centerX.equalTo(nameLabel);
make.height.equalTo(coverImageView.mas_height).multipliedBy(1.0 / 3.0);
make.width.equalTo(bookCoverView.mas_height).multipliedBy(150.0 / 200.0);
}];
self.bookModel.author_note = [self.bookModel.author_note stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (self.bookModel.author_note.length == 0) {
UILabel *authorLabel = [[UILabel alloc] init];
authorLabel.text = [NSString stringWithFormat:@"%@/%@", self.bookModel.author ?: @"", TFLocalizedString(@"作品")];
authorLabel.font = kFont14;
authorLabel.textColor = [self.readerSetting getReaderTextColor];
[coverImageView addSubview:authorLabel];
[authorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(nameLabel.mas_bottom).offset(12.0f);
make.centerX.equalTo(bookCoverView);
}];
} else {
UILabel *descLabel = [[UILabel alloc] init];
descLabel.numberOfLines = 5;
descLabel.font = kFont14;
descLabel.textColor = [self.readerSetting getReaderTextColor];
descLabel.text = self.bookModel.author_note;
[coverImageView addSubview:descLabel];
[descLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(nameLabel.mas_bottom).offset(SCREEN_HEIGHT * 65.0 / 896.0);
make.left.equalTo(coverImageView).offset(63.0);
make.right.equalTo(coverImageView).offset(-63.0);
}];
UILabel *authorLabel = [[UILabel alloc] init];
authorLabel.font = kFont14;
authorLabel.textColor = [self.readerSetting getReaderTextColor];
authorLabel.text = [NSString stringWithFormat:@"%@%@", @"—— ", self.bookModel.author_name ?: @""];
[coverImageView addSubview:authorLabel];
[authorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(descLabel.mas_bottom).offset(kMoreHalfMargin);
make.right.equalTo(descLabel);
}];
}
}
@end
@@ -0,0 +1,71 @@
//
// WXYZ_GiftMonthlyPassModel.h
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
@class WXYZ_GiftMonthlyPassInfoModel, WXYZ_GiftMonthlyPassListModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_GiftMonthlyPassModel : NSObject
/// 月票信息
@property (nonatomic, strong) WXYZ_GiftMonthlyPassInfoModel *info;
/// 月票列表
@property (nonatomic, strong) NSArray<WXYZ_GiftMonthlyPassListModel *> *list;
@end
@interface WXYZ_GiftMonthlyPassInfoModel : NSObject
@property (nonatomic, assign) NSInteger book_id;
/// 作品名称
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *cover;
/// 本月获得月票数量
@property (nonatomic, copy) NSString *stickerNumber;
/// 排名
@property (nonatomic, copy) NSString *ranking;
/// 和上一名排行的距离
@property (nonatomic, copy) NSString *last_distance;
/// 剩余的月票
@property (nonatomic, copy) NSString *ticket_remain;
/// 月票规则
@property (nonatomic, copy) NSString *ticket_rule;
/// 是否可投
@property (nonatomic, assign) NSInteger can_vote;
/// 投票说明
@property (nonatomic, copy) NSString *monthly_tips;
@end
@interface WXYZ_GiftMonthlyPassListModel : NSObject
@property (nonatomic, copy) NSString *title;
/// 月票展示数量
@property (nonatomic, assign) NSInteger num;
/// 是否可选中
@property (nonatomic, assign, getter=isEnabled) NSInteger enabled;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
//
// WXYZ_GiftMonthlyPassModel.m
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_GiftMonthlyPassModel.h"
@implementation WXYZ_GiftMonthlyPassModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper {
return @{
@"info" : @"ticket_info",
@"list" : @"ticket_option"
};
}
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{
@"info" : WXYZ_GiftMonthlyPassInfoModel.class,
@"list" : WXYZ_GiftMonthlyPassListModel.class
};
}
@end
@implementation WXYZ_GiftMonthlyPassInfoModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper {
return @{
@"stickerNumber" : @"current_month_get",
@"ranking" : @"rank_tips",
@"ticket_remain" : @"user_remain",
};
}
@end
@implementation WXYZ_GiftMonthlyPassListModel
@end
@@ -0,0 +1,28 @@
//
// WXYZ_GiftMonthlyPassView.h
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@class WXYZ_GiftView;
@class TFProductionModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_GiftMonthlyPassView : UIView
- (instancetype)initWithFrame:(CGRect)frame bookModel:(TFProductionModel *)bookModel;
/// 月票余额返回
@property (nonatomic, copy) void(^ticketNumBlock)(NSInteger ticketNumber);
@property (nonatomic, weak) WXYZ_GiftView *giftView;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,320 @@
//
// WXYZ_GiftMonthlyPassView.m
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_GiftMonthlyPassView.h"
#import "WXYZ_GiftMonthlyPassModel.h"
#import "NSObject+Observer.h"
#import "TFReaderBookManager.h"
#import "WXYZ_TickectAlertModel.h"
#import "TFProductionCoverView.h"
#import "WXYZ_GiftView.h"
#import "TFRechargeViewController.h"
#import "TFWebViewController.h"
#import "TFGiftAlertView.h"
@interface WXYZ_GiftMonthlyPassView ()
@property (nonatomic, strong) TFProductionModel *bookModel;
@property (nonatomic, strong) WXYZ_GiftMonthlyPassModel *monthlyPassModel;
/// 当前选择按钮的下标
@property (nonatomic, assign) NSInteger selectedIndex;
@property (nonatomic, strong) NSArray<UIButton *> *tickectBtnArray;
@property (nonatomic, weak) UIView *alertView;
@property (nonatomic, weak) UIButton *voteBtn;
@end
@implementation WXYZ_GiftMonthlyPassView
- (instancetype)initWithFrame:(CGRect)frame bookModel:(TFProductionModel *)bookModel {
if (self = [super initWithFrame:frame]) {
self.bookModel = bookModel;
[self initialize];
[self netRequest];
[self createSubviews];
}
return self;
}
- (void)initialize {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(netRequest) name:Notification_Login_Success object:nil];
}
- (void)createSubviews {
TFProductionCoverView *coverImageView = [[TFProductionCoverView alloc] initWithProductionType:TFProductionTypeNovel coverDirection:TFProductionCoverDirectionVertical];
[self addSubview:coverImageView];
[coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self).offset(kMargin);
make.left.equalTo(self).offset(kMoreHalfMargin);
make.size.mas_equalTo(CGSizeMake(55.0, 74.0));
}];
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.textColor = kBlackColor;
nameLabel.font = kFont14;
[self addSubview:nameLabel];
[nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(coverImageView).offset(16);
make.left.equalTo(coverImageView.mas_right).offset(kHalfMargin);
}];
UILabel *tickerLabel = [[UILabel alloc] init];
tickerLabel.backgroundColor = [UIColor clearColor];
[self addSubview:tickerLabel];
UILabel *rankLabel = [[UILabel alloc] init];
rankLabel.backgroundColor = [UIColor clearColor];
[self addSubview:rankLabel];
UILabel *last_distanceLabel = [[UILabel alloc] init];
last_distanceLabel.backgroundColor = [UIColor clearColor];
last_distanceLabel.textAlignment = NSTextAlignmentLeft;
[self addSubview:last_distanceLabel];
NSArray<UILabel *> *labelArr = @[tickerLabel, rankLabel, last_distanceLabel];
[labelArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:0 leadSpacing:80 tailSpacing:0];
[labelArr mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(coverImageView).offset(-kHalfMargin);
}];
UIView *bottomView = [[UIView alloc] init];
bottomView.backgroundColor = kGrayViewColor;
[self addSubview:bottomView];
[bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.bottom.equalTo(self);
make.height.mas_equalTo(65.0 + PUB_TABBAR_OFFSET);
}];
UILabel *remainLabel = [[UILabel alloc] init];
remainLabel.backgroundColor = [UIColor clearColor];
[bottomView addSubview:remainLabel];
[remainLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(bottomView).offset(kMoreHalfMargin + 1.0f);
make.left.equalTo(bottomView).offset(kMoreHalfMargin);
}];
UIImageView *helpImageView = [[UIImageView alloc] init];
helpImageView.image = [UIImage imageNamed:@"book_help"];
[bottomView addSubview:helpImageView];
[helpImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(remainLabel);
make.left.equalTo(remainLabel.mas_right).offset(kHalfMargin);
make.size.mas_equalTo(CGSizeMake(kMoreHalfMargin, kMoreHalfMargin));
}];
helpImageView.userInteractionEnabled = YES;
WS(weakSelf)
[helpImageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithActionBlock:^(id _Nonnull sender) {
[weakSelf.giftView removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@""];
TFWebViewController *vc = [[TFWebViewController alloc] init];
vc.URLString = weakSelf.monthlyPassModel.info.ticket_rule;
vc.navTitle = TFLocalizedString(@"月票说明");
vc.isPresentState = NO;
[[TFViewHelper getCurrentNavigationController] pushViewController:vc animated:YES];
}]];
helpImageView.hidden = YES;
UILabel *detailLabel = [[UILabel alloc] init];
detailLabel.numberOfLines = 2;
detailLabel.backgroundColor = [UIColor clearColor];
[bottomView addSubview:detailLabel];
[detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(remainLabel.mas_bottom).offset(2.5);
make.left.equalTo(remainLabel);
}];
UIButton *voteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
self.voteBtn = voteBtn;
[voteBtn setImage:[UIImage imageNamed:TFLocalizedString(@"book_ticketBtn")] forState:UIControlStateNormal];
voteBtn.layer.cornerRadius = 19.0f;
voteBtn.layer.masksToBounds = YES;
[voteBtn addTarget:self action:@selector(voteEvent) forControlEvents:UIControlEventTouchUpInside];
[bottomView addSubview:voteBtn];
[voteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(bottomView).offset(kMoreHalfMargin);
make.right.equalTo(bottomView).offset(-kMoreHalfMargin);
make.size.mas_equalTo(CGSizeMake(105.0f, 38.0f));
}];
[detailLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(voteBtn.mas_left).offset(-kQuarterMargin);
}];
[remainLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(voteBtn.mas_left).offset(-kQuarterMargin);
}];
[self addObserver:KEY_PATH(self, monthlyPassModel) complete:^(WXYZ_GiftMonthlyPassView * _Nonnull obj, id _Nullable oldVal, WXYZ_GiftMonthlyPassModel * _Nullable newVal) {
coverImageView.coverImageUrl = newVal.info.cover;
nameLabel.text = newVal.info.name ? : @"";
tickerLabel.attributedText = [obj attributeStringWithStr:newVal.info.stickerNumber ? : @"" speFont:kFont16 speColor:kBlackColor];
rankLabel.attributedText = [obj attributeStringWithStr:newVal.info.ranking ? : @"" speFont:kFont16 speColor:kBlackColor];
last_distanceLabel.attributedText = [obj attributeStringWithStr:newVal.info.last_distance ? : @"" speFont:kFont16 speColor:kBlackColor];
NSString *prefix = TFLocalizedString(@"拥有");
NSString *suffix = TFLocalizedString(@"月票");
NSMutableAttributedString *atr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@", prefix, newVal.info.ticket_remain, suffix] attributes:@{NSFontAttributeName : kFont14, NSForegroundColorAttributeName : kBlackColor}];
[atr addAttribute:NSForegroundColorAttributeName value:kMainColor range:NSMakeRange(prefix.length, newVal.info.ticket_remain.length)];
remainLabel.attributedText = atr;
detailLabel.attributedText = [obj attributeStringWithStr:newVal.info.monthly_tips speFont:kFont11 speColor:kMainColor];
if (newVal.info.can_vote == 1) {
voteBtn.alpha = 1;
voteBtn.enabled = YES;
} else {
voteBtn.alpha = 0.5;
voteBtn.enabled = NO;
}
NSMutableArray<UIButton *> *btnArr = [NSMutableArray array];
if (obj.tickectBtnArray.count == 0) {
obj.tickectBtnArray = btnArr;
NSInteger index = 0;
for (WXYZ_GiftMonthlyPassListModel *model in newVal.list) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *text = [NSString stringWithFormat:@"%@\n%@", model.title, TFLocalizedString(@"月票")];
NSMutableAttributedString *atr = [[NSMutableAttributedString alloc] initWithString:text attributes:@{NSForegroundColorAttributeName : kBlackColor, NSFontAttributeName : kFont11}];
[atr addAttribute:NSFontAttributeName value:kFont15 range:NSMakeRange(0, model.title.length)];
if (model.enabled == 0) {
[atr addAttribute:NSForegroundColorAttributeName value:kColorRGB(153, 153, 153) range:NSMakeRange(0, atr.length)];
button.enabled = NO;
}
[button setAttributedTitle:atr forState:UIControlStateNormal];
[button setTitleEdgeInsets:UIEdgeInsetsMake(0, 5.0, 0, 5.0)];
button.titleLabel.numberOfLines = 0;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.layer.cornerRadius = 2.5;
button.layer.masksToBounds = YES;
button.layer.borderWidth = 0.5;
button.layer.borderColor = kColorRGB(221, 221, 221).CGColor;
button.tag = index;
[button addTarget:obj action:@selector(tickectOptionEvent:) forControlEvents:UIControlEventTouchUpInside];
[obj addSubview:button];
[btnArr addObject:button];
index++;
}
[btnArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:kQuarterMargin leadSpacing:15.0 tailSpacing:15.0];
[btnArr mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(coverImageView.mas_bottom).offset(24.0);
make.height.equalTo(btnArr.firstObject.mas_width);
}];
[btnArr.firstObject sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}];
}
- (void)tickectOptionEvent:(UIButton *)button {
if (self.monthlyPassModel.list[button.tag].enabled == 1) {
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithAttributedString:button.currentAttributedTitle];
[str setAttribute:NSForegroundColorAttributeName value:kMainColor];
[button setAttributedTitle:str forState:UIControlStateNormal];
button.layer.borderColor = kMainColor.CGColor;
self.selectedIndex = button.tag;
}
for (UIButton *obj in self.tickectBtnArray) {
if (obj != button) {
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithAttributedString:obj.currentAttributedTitle];
[str setAttribute:NSForegroundColorAttributeName value:self.monthlyPassModel.list[obj.tag].enabled ? kBlackColor : kColorRGB(153, 153, 153)];
[obj setAttributedTitle:str forState:UIControlStateNormal];
obj.layer.borderColor = kColorRGB(221, 221, 221).CGColor;
}
}
if (self.monthlyPassModel.info.can_vote == 1) {
self.voteBtn.alpha = 1;
self.voteBtn.enabled = YES;
} else {
self.voteBtn.alpha = 0.5;
self.voteBtn.enabled = NO;
}
}
// 投月票
- (void)voteEvent {
if (self.selectedIndex == -1) {
return;
}
if (!TFUserInfoManager.isLogin) {
[TFLoginOptionsViewController presentLoginView:nil];
return;
}
WXYZ_GiftMonthlyPassListModel *model = self.monthlyPassModel.list[self.selectedIndex];
NSDictionary *params = @{
@"book_id" : @(self.bookModel.production_id),
@"chapter_id" : @([TFReaderBookManager sharedManager].chapter_id),
@"num" : @(model.num),
};
WS(weakSelf)
[TFNetworkTools POST:Book_Reward_Ticket_Vote parameters:params model:WXYZ_TickectAlertModel.class success:^(BOOL isSuccess, WXYZ_TickectAlertModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
[weakSelf netRequest];
NSString *text = [NSString stringWithFormat:@"%@", requestModel.data[@"ticket_num"]];
[[NSNotificationCenter defaultCenter] postNotificationName:@"changeTicket" object:text];
!weakSelf.ticketNumBlock ?: weakSelf.ticketNumBlock([text integerValue]);
[TFReaderBookManager sharedManager].ticket_num = text ?: @"";
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"投票成功")];
} else if (Compare_Json_isEqualTo(requestModel.code, 902)) {
[weakSelf showAlert:t_model t_model:weakSelf.monthlyPassModel.list[weakSelf.selectedIndex] production_id:weakSelf.bookModel.production_id ticketNumBlock:weakSelf.ticketNumBlock];
[weakSelf.giftView hide];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
- (NSMutableAttributedString *)attributeStringWithStr:(NSString *)str speFont:(UIFont *)speFont speColor:(UIColor *)speColor {
NSRange range = [str rangeOfString:@"###.*###" options:NSRegularExpressionSearch];
if (range.length == 0) range = NSMakeRange(0, 0);
NSString *suffix = [[str substringWithRange:range] stringByReplacingOccurrencesOfString:@"#" withString:@""];
suffix = [NSString stringWithFormat:@" %@ ", suffix];
NSMutableString *prefix = [NSMutableString stringWithString:[str stringByReplacingCharactersInRange:range withString:@""]];
[prefix insertString:suffix atIndex:range.location];
NSMutableAttributedString *atr = [[NSMutableAttributedString alloc] initWithString:prefix attributes:@{NSFontAttributeName : kFont11, NSForegroundColorAttributeName : kGrayTextColor}];
[atr addAttributes:@{NSFontAttributeName : speFont, NSForegroundColorAttributeName : speColor} range:NSMakeRange(range.location, suffix.length)];
return atr;
}
- (void)netRequest {
WS(weakSelf)
[TFNetworkTools POST:Book_Gift_Montyly_Pass parameters:@{@"book_id":@(self.bookModel.production_id)} model:WXYZ_GiftMonthlyPassModel.class success:^(BOOL isSuccess, id _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
weakSelf.monthlyPassModel = t_model;
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
- (void)showAlert:(WXYZ_TickectAlertModel *)model t_model:(WXYZ_GiftMonthlyPassListModel *)t_model production_id:(NSInteger)production_id ticketNumBlock:(void(^)(NSInteger number))ticketNumBlock
{
TFGiftAlertView *alertView = [[TFGiftAlertView alloc] init];
[alertView setAlertModel:model giftModel:t_model production_id:production_id ticketBlock:ticketNumBlock];
[alertView showAlertView];
}
@end
@@ -0,0 +1,49 @@
//
// WXYZ_GiftRewardList.h
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
@class WXYZ_GiftRewardListModel, WXYZ_GiftUserModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_GiftRewardModel : NSObject
@property (nonatomic, copy) NSArray<WXYZ_GiftRewardListModel *> *list;
@property (nonatomic, copy) NSArray<NSString *> *announce_list;
@property (nonatomic, strong) WXYZ_GiftUserModel *user;
@end
@interface WXYZ_GiftRewardListModel : NSObject
@property (nonatomic, assign) NSInteger gift_id;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *icon;
/// 奖励文案
@property (nonatomic, copy) NSString *gift_price;
/// 角标
@property (nonatomic, copy) NSString *flag;
@end
@interface WXYZ_GiftUserModel : NSObject
@property (nonatomic, assign) NSInteger goldRemain;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,42 @@
//
// WXYZ_GiftRewardList.m
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_GiftRewardModel.h"
@implementation WXYZ_GiftRewardModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper {
return @{
@"list" : @"gift_option",
@"announce_list" : @"broadcast_list"
};
}
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{
@"list" : WXYZ_GiftRewardListModel.class
};
}
@end
@implementation WXYZ_GiftRewardListModel
+ (NSDictionary<NSString *, id> *)modelCustomPropertyMapper {
return @{
@"awardTitle" : @"award_money"
};
}
@end
@implementation WXYZ_GiftUserModel
@end
@@ -0,0 +1,39 @@
//
// WXYZ_GiftRewardView.h
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@class WXYZ_GiftView;
@class WXYZ_GiftRewardListModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_GiftRewardView : UIView
@property (nonatomic, weak) WXYZ_GiftView *giftView;
@property (nonatomic, strong) TFProductionModel *bookModel;
/// 打赏余额返回
@property (nonatomic, copy) void(^giftNumBlock)(NSInteger giftNumber);
- (instancetype)initWithBookModel:(TFProductionModel *)bookModel;
@end
@interface WXYZ_GiftRewardCell : UICollectionViewCell
@property (nonatomic, strong) WXYZ_GiftRewardListModel *giftRewardModel;
- (void)setSelected:(BOOL)selected;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,354 @@
//
// WXYZ_GiftRewardView.m
// WXReader
//
// Created by LL on 2020/5/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_GiftRewardView.h"
#import "NSObject+Observer.h"
#import "WXYZ_GiftRewardModel.h"
#import "LLPageControl.h"
#import "WXYZ_AnnouncementView.h"
#import "TFReaderBookManager.h"
#import "TFRechargeViewController.h"
#import "WXYZ_GiftView.h"
@interface WXYZ_GiftRewardView ()<UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSArray<WXYZ_GiftRewardListModel *> *dataSourceArray;
@property (nonatomic, strong) WXYZ_GiftRewardModel *giftRewardModel;
@property (nonatomic, weak) UICollectionView *mainCollectionView;
@property (nonatomic, weak) LLPageControl *pageControl;
@property (nonatomic, weak) WXYZ_AnnouncementView *announcementView;
@property (nonatomic, weak) UILabel *remainLabel;
@property (nonatomic, assign) NSInteger selectedIndex;
@end
@implementation WXYZ_GiftRewardView
- (instancetype)initWithBookModel:(TFProductionModel *)bookModel {
if (self = [super init]) {
self.bookModel = bookModel;
[self initialize];
[self createSubviews];
[self netRequest];
}
return self;
}
- (void)initialize {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginSuccess) name:Notification_Login_Success object:nil];
}
- (void)createSubviews {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.itemSize = CGSizeMake((SCREEN_WIDTH - 2.0 * kMoreHalfMargin - 3 * kHalfMargin) / 4.0, 127.0);
flowLayout.minimumInteritemSpacing = kHalfMargin;
flowLayout.minimumLineSpacing = kHalfMargin;
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
UICollectionView *mainCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
self.mainCollectionView = mainCollectionView;
mainCollectionView.showsHorizontalScrollIndicator = NO;
mainCollectionView.showsVerticalScrollIndicator = NO;
mainCollectionView.backgroundColor = [UIColor clearColor];
mainCollectionView.pagingEnabled = YES;
mainCollectionView.dataSource = self;
mainCollectionView.delegate = self;
mainCollectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, kMoreHalfMargin);
[mainCollectionView registerClass:WXYZ_GiftRewardCell.class forCellWithReuseIdentifier:@"Identifier"];
[self addSubview:mainCollectionView];
[mainCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(15);
make.right.equalTo(self).offset(0);
make.top.equalTo(self).offset(kMoreHalfMargin);
make.height.mas_equalTo(127.0);
}];
// [mainCollectionView addObserver:KEY_PATH(mainCollectionView, contentSize) complete:^(UICollectionView * _Nonnull obj, id _Nullable oldVal, id _Nullable newVal) {
// CGSize size = [newVal CGSizeValue];
// [obj mas_updateConstraints:^(MASConstraintMaker *make) {
// make.height.mas_equalTo(size.height);
// }];
// [obj.superview setNeedsLayout];
// [obj.superview layoutIfNeeded];
// }];
LLPageControl *pageControl = [LLPageControl pageControlWithRadius:3.5 spacing:6.0f numberOfPages:1];
self.pageControl = pageControl;
pageControl.currentPageIndicatorTintColor = kMainColor;
pageControl.pageIndicatorTintColor = kColorRGB(225, 225, 225);
[self addSubview:pageControl];
[pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(mainCollectionView.mas_bottom).offset(12.0);
make.centerX.equalTo(self);
}];
WXYZ_AnnouncementView *announcementView = [[WXYZ_AnnouncementView alloc] init];
self.announcementView = announcementView;
announcementView.backgroundColor = kColorRGB(249, 248, 253);
announcementView.layer.cornerRadius = 14.0f;
announcementView.layer.masksToBounds = YES;
announcementView.textFont = kFont11;
announcementView.textColor = kGrayTextColor;
announcementView.isCenter = YES;
announcementView.duration = 5.0f;
announcementView.userInteractionEnabled = NO;
[self addSubview:announcementView];
[announcementView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(pageControl.mas_bottom).offset(17.0f);
make.left.equalTo(self).offset(kMoreHalfMargin);
make.right.equalTo(self).offset(-kMoreHalfMargin);
make.height.equalTo(announcementView.mas_width).multipliedBy(28.0 / 345.0);
}];
UIView *bottomView = [[UIView alloc] init];
bottomView.backgroundColor = kColorRGB(249, 248, 253);
[self addSubview:bottomView];
[bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(announcementView.mas_bottom).offset(17.0f);
make.left.right.equalTo(self);
make.height.mas_equalTo(65.0f);
}];
UILabel *remainLabel = [[UILabel alloc] init];
self.remainLabel = remainLabel;
remainLabel.backgroundColor = [UIColor clearColor];
[self addSubview:remainLabel];
[remainLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(bottomView).offset(kMoreHalfMargin);
make.top.equalTo(bottomView.mas_top).offset(15.0);
}];
UIButton *rewardBtn = [UIButton buttonWithType:UIButtonTypeCustom];
rewardBtn.layer.cornerRadius = 19.0f;
[rewardBtn setImage:[UIImage imageNamed:TFLocalizedString(@"book_giftBtn")] forState:UIControlStateNormal];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rewardEvent)];
[rewardBtn addGestureRecognizer:tap];
[bottomView addSubview:rewardBtn];
[rewardBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(bottomView).offset(6.0);
make.right.equalTo(bottomView).offset(-kMoreHalfMargin);
make.size.mas_equalTo(CGSizeMake(105, 38));
}];
UIView *splitLine = [[UIView alloc] init];
splitLine.backgroundColor = [UIColor clearColor];
[self addSubview:splitLine];
[splitLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(0.1);
make.left.right.bottom.equalTo(self);
make.top.equalTo(bottomView.mas_bottom).priorityLow();
}];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.dataSourceArray.count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
WXYZ_GiftRewardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Identifier" forIndexPath:indexPath];
[cell setGiftRewardModel:self.dataSourceArray[indexPath.row]];
[cell setSelected:self.selectedIndex == indexPath.row];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
self.selectedIndex = indexPath.row;
[collectionView reloadData];
}
- (void)loginSuccess {
NSString *prefix = TFLocalizedString(@"余额:");
NSString *remain = [NSString stringWithFormat:@"%zd", TFUserInfoManager.shareInstance.masterRemain];
NSString *suffix = TFSystemInfoManager.masterUnit;
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@ %@", prefix, remain, suffix] attributes:@{NSForegroundColorAttributeName: kGrayTextColor, NSFontAttributeName: kFont14}];
[str addAttribute:NSForegroundColorAttributeName value:kMainColor range:NSMakeRange(prefix.length, remain.length)];
self.remainLabel.attributedText = str;
}
- (void)rewardEvent {
if (!TFUserInfoManager.isLogin) {
[TFLoginOptionsViewController presentLoginView:nil];
return;
}
WXYZ_GiftRewardListModel *model = self.dataSourceArray[self.selectedIndex];
NSDictionary *params = @{
@"book_id" : @(self.bookModel.production_id),
@"chapter_id" : @([TFReaderBookManager sharedManager].chapter_id),
@"gift_id" : @(model.gift_id)
};
WS(weakSelf)
[TFNetworkTools POST:Book_Reward_Gift_Send parameters:params model:nil success:^(BOOL isSuccess, NSDictionary *_Nullable t_model, TFNetworkRequestModel *requestModel) {
if (isSuccess) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"打赏成功")];
NSString *text = [NSString stringWithFormat:@"%@", t_model[@"data"][@"reward_num"]];
[[NSNotificationCenter defaultCenter] postNotificationName:@"changeReward" object:text];
!weakSelf.giftNumBlock ?: weakSelf.giftNumBlock([text integerValue]);
[weakSelf.giftView hide];
} else if (Compare_Json_isEqualTo(requestModel.code, 802)) {
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@""];
[[TFViewHelper getCurrentNavigationController] pushViewController:[[TFRechargeViewController alloc] init] animated:YES];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// 计算偏移量更新分页控件
NSUInteger page = CGRectGetMinX(scrollView.bounds) / scrollView.contentOffset.x;
if (scrollView.contentOffset.x == 0) {
page = 0;
}
self.pageControl.currentPage = page;
}
- (void)netRequest {
WS(weakSelf)
[TFNetworkTools POST:Gift_List parameters:@{@"book_id":@(self.bookModel.production_id)} model:WXYZ_GiftRewardModel.class success:^(BOOL isSuccess, WXYZ_GiftRewardModel *_Nullable t_model, TFNetworkRequestModel *requestModel) {
if (isSuccess) {
weakSelf.giftRewardModel = t_model;
weakSelf.dataSourceArray = t_model.list;
weakSelf.pageControl.numberOfPages = ceil(weakSelf.dataSourceArray.count / 4.0);
NSMutableArray<TFAnnouncementModel *> *arr = [NSMutableArray array];
for (NSString *str in t_model.announce_list) {
TFAnnouncementModel *tt_model = [[TFAnnouncementModel alloc] init];
tt_model.content = @"";
tt_model.title = str;
[arr addObject:tt_model];
}
weakSelf.announcementView.modelArr = arr;
NSString *prefix = TFLocalizedString(@"余额:");
NSString *remain = [NSString stringWithFormat:@"%zd", t_model.user.goldRemain];
NSString *suffix = TFSystemInfoManager.masterUnit;
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@ %@", prefix, remain, suffix] attributes:@{NSForegroundColorAttributeName: kGrayTextColor, NSFontAttributeName: kFont14}];
[str addAttribute:NSForegroundColorAttributeName value:kMainColor range:NSMakeRange(prefix.length, remain.length)];
weakSelf.remainLabel.attributedText = str;
[weakSelf.mainCollectionView reloadData];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
@end
@implementation WXYZ_GiftRewardCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self createSubviews];
}
return self;
}
- (void)createSubviews {
self.contentView.layer.cornerRadius = 2.5;
self.contentView.layer.borderColor = kMainColor.CGColor;
self.contentView.layer.borderWidth = 0.0f;
self.contentView.backgroundColor = [UIColor clearColor];
UILabel *flagLabel = [[UILabel alloc] init];
flagLabel.font = kFont10;
flagLabel.textColor = [UIColor whiteColor];
flagLabel.backgroundColor = kColorRGB(255, 83, 81);
flagLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.contentView.bounds) - kHalfMargin;
flagLabel.textAlignment = NSTextAlignmentCenter;
flagLabel.layer.cornerRadius = 2.0f;
flagLabel.numberOfLines = 0;
flagLabel.layer.masksToBounds = YES;
[self.contentView addSubview:flagLabel];
[flagLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.right.equalTo(self.contentView);
}];
UIImageView *coverImageView = [[UIImageView alloc] init];
coverImageView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:coverImageView];
[self.contentView sendSubviewToBack:coverImageView];
[coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView).offset(kMargin);
make.centerX.equalTo(self.contentView);
make.size.mas_equalTo(CGSizeMake(50.0, 50.0));
}];
UILabel *subtitle = [[UILabel alloc] init];
subtitle.textColor = kGrayTextColor;
subtitle.font = kFont10;
subtitle.textAlignment = NSTextAlignmentCenter;
subtitle.numberOfLines = 0;
subtitle.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:subtitle];
[subtitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.contentView).offset(-kQuarterMargin);
make.left.equalTo(self.contentView).offset(kQuarterMargin);
make.right.equalTo(self.contentView).offset(-kQuarterMargin);
}];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.textColor = kBlackColor;
titleLabel.font = kFont13;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:titleLabel];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(subtitle.mas_top).offset(- kQuarterMargin);
make.left.equalTo(self.contentView).offset(kQuarterMargin);
make.right.equalTo(self.contentView).offset(-kQuarterMargin);
}];
[self addObserver:KEY_PATH(self, giftRewardModel) complete:^(WXYZ_GiftRewardCell * _Nonnull obj, id _Nullable oldVal, WXYZ_GiftRewardListModel * _Nullable newVal) {
flagLabel.text = newVal.flag ?: @"";
CGFloat maxWidth = CGRectGetWidth(obj.contentView.bounds) - kHalfMargin;
if (flagLabel.intrinsicContentSize.width + 12 < maxWidth) {
maxWidth = flagLabel.intrinsicContentSize.width + 12;
}
[flagLabel mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(maxWidth);
make.height.mas_equalTo(flagLabel.intrinsicContentSize.height + kQuarterMargin);
}];
flagLabel.hidden = newVal.flag.length == 0;
[coverImageView setImageWithURL:[NSURL URLWithString:newVal.icon ?: @""] placeholder:HoldImage];
titleLabel.text = newVal.title ?: @"";
subtitle.text = newVal.gift_price ?: @"";
}];
}
//- (UICollectionViewLayoutAttributes*)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes*)layoutAttributes {
// [self setNeedsLayout];
// [self layoutIfNeeded];
// CGSize size = [self.contentView systemLayoutSizeFittingSize:layoutAttributes.size];
// CGRect cellFrame = layoutAttributes.frame;
// cellFrame.size.height = size.height;
// layoutAttributes.frame = cellFrame;
// return layoutAttributes;
//}
- (void)setSelected:(BOOL)selected {
if (selected) {
self.contentView.layer.borderWidth = 1.0f;
} else {
self.contentView.layer.borderWidth = 0.0f;
}
}
@end
@@ -0,0 +1,35 @@
//
// WXYZ_GiftView.h
// WXReader
//
// Created by LL on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TFProductionModel;
NS_ASSUME_NONNULL_BEGIN
/// 阅读器礼物视图
@interface WXYZ_GiftView : UIView
/// 月票余额返回
@property (nonatomic, copy) void(^ticketNumBlock)(NSInteger ticketNumber);
/// 打赏余额返回
@property (nonatomic, copy) void(^giftNumBlock)(NSInteger giftNumber);
/// 是否选中月票页面
@property (nonatomic, assign) BOOL isTicket;
- (instancetype)initWithFrame:(CGRect)frame bookModel:(TFProductionModel *)bookModel;
- (void)hide;
- (void)show;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,257 @@
//
// WXYZ_GiftView.m
// WXReader
//
// Created by LL on 2020/5/27.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_GiftView.h"
#import "UIView+LayoutCallback.h"
#import "SGPageTitleView.h"
#import "WXYZ_GiftRewardView.h"
#import "WXYZ_GiftMonthlyPassView.h"
#import "AppDelegate.h"
@interface WXYZ_GiftView ()<SGPageTitleViewDelegate, UIScrollViewDelegate>
@property (nonatomic, weak) UIView *mainView;
@property (nonatomic, weak) UIView *backView;
@property (nonatomic, weak) SGPageTitleView *pageTitleView;
@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, strong) TFProductionModel *bookModel;
@property (nonatomic, weak) WXYZ_GiftRewardView *rewardView;
@property (nonatomic, weak) WXYZ_GiftMonthlyPassView *monthlyPassView;
@property (nonatomic, strong) NSMutableArray<NSString *> *titleArr;
/// mainView视图约束
@property (nonatomic, strong) MASConstraint *mainViewConstraint;
@end
@implementation WXYZ_GiftView
- (instancetype)initWithFrame:(CGRect)frame bookModel:(TFProductionModel *)bookModel {
if (self = [super initWithFrame:frame]) {
self.bookModel = bookModel;
[self createSubviews];
}
return self;
}
- (void)createSubviews {
self.backgroundColor = kBlackTransparentColor;
[[TFViewHelper getCurrentViewController].view addSubview:self];
[self mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo([TFViewHelper getCurrentViewController].view);
}];
UIView *backView = [[UIView alloc] init];
self.backView = backView;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
[backView addGestureRecognizer:tap];
backView.backgroundColor = [UIColor clearColor];
[self addSubview:backView];
[backView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
UIView *mainView = [[UIView alloc] init];
self.mainView = mainView;
mainView.backgroundColor = [UIColor whiteColor];
mainView.frameBlock = ^(UIView * _Nonnull view) {
UIBezierPath *corner = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(12.0, 12.0)];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = corner.CGPath;
view.layer.mask = layer;
};
[self addSubview:mainView];
[mainView mas_makeConstraints:^(MASConstraintMaker *make) {
self.mainViewConstraint = make.top.equalTo(backView.mas_bottom);
make.left.width.equalTo(backView);
}];
SGPageTitleViewConfigure *pageConfigure = [[SGPageTitleViewConfigure alloc] init];
pageConfigure.indicatorColor = kColorRGB(253, 154, 99);
pageConfigure.indicatorStyle = SGIndicatorStyleDynamic;
pageConfigure.indicatorHeight = 3;
pageConfigure.indicatorFixedWidth = 20;
pageConfigure.indicatorDynamicWidth = 20;
pageConfigure.indicatorCornerRadius = 3.0;
pageConfigure.indicatorToBottomDistance = 5;
pageConfigure.titleFont = kFont15;
pageConfigure.titleSelectedFont = kFont16;
pageConfigure.titleColor = kGrayTextColor;
pageConfigure.titleSelectedColor = kBlackColor;
pageConfigure.showBottomSeparator = NO;
AppDelegate *app = (AppDelegate *)kRCodeSync([UIApplication sharedApplication].delegate);
NSMutableArray<NSString *> *titleArr = [NSMutableArray array];
self.titleArr = titleArr;
if (app.checkSettingModel.system_setting.novel_reward_switch == 1) {
[titleArr addObject:TFLocalizedString(@"打赏")];
}
if (app.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
[titleArr addObject:TFLocalizedString(@"月票")];
}
CGFloat width1 = [TFViewHelper getDynamicWidthWithLabelFont:kFont14 labelHeight:50.0 labelText:TFLocalizedString(@"打赏") maxWidth:200.0];
CGFloat width2 = [TFViewHelper getDynamicWidthWithLabelFont:kFont17 labelHeight:50.0 labelText:TFLocalizedString(@"月票") maxWidth:200.0];
CGFloat width = width1 + width2 + kLabelHeight + kMargin;
SGPageTitleView *pageTitleView = [SGPageTitleView pageTitleViewWithFrame:CGRectZero delegate:self titleNames:titleArr configure:pageConfigure];
self.pageTitleView = pageTitleView;
pageTitleView.backgroundColor = [UIColor clearColor];
[mainView addSubview:pageTitleView];
[pageTitleView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(mainView).offset(0);
make.centerX.equalTo(mainView);
make.width.mas_equalTo(width);
make.height.mas_equalTo(50);
}];
UIView *pageTitleSplitLine = [[UIView alloc] init];
pageTitleSplitLine.backgroundColor = kGrayLineColor;
[mainView addSubview:pageTitleSplitLine];
[pageTitleSplitLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.width.equalTo(mainView);
make.top.equalTo(pageTitleView.mas_bottom);
make.height.mas_equalTo(kCellLineHeight);
}];
UIScrollView *scrollView = [[UIScrollView alloc] init];
self.scrollView = scrollView;
scrollView.backgroundColor = [UIColor clearColor];
scrollView.bounces = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.delegate = self;
scrollView.pagingEnabled = YES;
[mainView addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(pageTitleSplitLine.mas_bottom);
make.left.width.equalTo(mainView);
make.height.mas_equalTo(271 + PUB_TABBAR_OFFSET);
}];
WXYZ_GiftRewardView *rewardView = [[WXYZ_GiftRewardView alloc] initWithBookModel:self.bookModel];
self.rewardView = rewardView;
rewardView.giftView = self;
rewardView.backgroundColor = [UIColor clearColor];
WXYZ_GiftMonthlyPassView *monthlyPassView = [[WXYZ_GiftMonthlyPassView alloc] initWithFrame:CGRectZero bookModel:self.bookModel];
self.monthlyPassView = monthlyPassView;
monthlyPassView.giftView = self;
monthlyPassView.backgroundColor = [UIColor clearColor];
if (app.checkSettingModel.system_setting.novel_reward_switch == 1 && app.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
[scrollView addSubview:rewardView];
[scrollView addSubview:monthlyPassView];
[rewardView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.width.height.equalTo(scrollView);
}];
[monthlyPassView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.height.right.equalTo(scrollView);
make.left.equalTo(rewardView.mas_right);
make.width.equalTo(rewardView);
}];
} else if (app.checkSettingModel.system_setting.novel_reward_switch == 1) {
[scrollView addSubview:rewardView];
[rewardView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.width.height.equalTo(scrollView);
make.right.equalTo(scrollView);
}];
// monthlyPassView.hidden = YES;
} else if (app.checkSettingModel.system_setting.monthly_ticket_switch == 1) {
[scrollView addSubview:monthlyPassView];
[monthlyPassView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.width.height.equalTo(scrollView);
make.right.equalTo(scrollView);
}];
// rewardView.hidden = YES;
}
UIView *splitLine = [[UIView alloc] init];
splitLine.backgroundColor = [UIColor clearColor];
[mainView addSubview:splitLine];
[splitLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(0.1);
make.left.right.bottom.equalTo(mainView);
make.top.equalTo(scrollView.mas_bottom).priorityLow();
}];
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (void)setGiftNumBlock:(void (^)(NSInteger))giftNumBlock {
_giftNumBlock = giftNumBlock;
self.rewardView.giftNumBlock = giftNumBlock;
}
- (void)setTicketNumBlock:(void (^)(NSInteger))ticketNumBlock {
_ticketNumBlock = ticketNumBlock;
self.monthlyPassView.ticketNumBlock = ticketNumBlock;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// 计算偏移量更新分页控件
NSUInteger page = scrollView.contentOffset.x / CGRectGetWidth(scrollView.bounds);
self.pageTitleView.resetSelectedIndex = page;
}
- (void)pageTitleView:(SGPageTitleView *)pageTitleView selectedIndex:(NSInteger)selectedIndex {
[self.scrollView setContentOffset:CGPointMake(SCREEN_WIDTH * selectedIndex, 0) animated:YES];
}
- (void)setIsTicket:(BOOL)isTicket {
if (isTicket) {
if (self.titleArr.count > 1) {
self.pageTitleView.resetSelectedIndex = 1;
[self.scrollView setContentOffset:CGPointMake(SCREEN_WIDTH * 1, 0) animated:NO];
}
} else {
self.pageTitleView.resetSelectedIndex = 0;
[self.scrollView setContentOffset:CGPointMake(SCREEN_WIDTH * 0, 0) animated:NO];
}
}
- (void)show {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.mainViewConstraint uninstall];
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
self.mainViewConstraint = make.top.equalTo(self.mas_bottom).offset(-CGRectGetHeight(self.mainView.frame));
}];
[self.mainView.superview layoutIfNeeded];
}];
}
- (void)hide {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.mainViewConstraint uninstall];
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
self.mainViewConstraint = make.top.equalTo(self.mas_bottom);
}];
[self.mainView.superview layoutIfNeeded];
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}
@end
@@ -0,0 +1,35 @@
//
// WXYZ_TickectAlertModel.h
// WXReader
//
// Created by LL on 2020/6/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
@class WXYZ_TickectAlertItemsModel;
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_TickectAlertModel : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSArray<NSString *> *desc;
@property (nonatomic, copy) NSArray<WXYZ_TickectAlertItemsModel *> *items;
@end
@interface WXYZ_TickectAlertItemsModel : NSObject
@property (nonatomic, copy) NSString *title;
/// 动作 recharge去充值 exchange金币抵扣
@property (nonatomic, copy) NSString *action;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,24 @@
//
// WXYZ_TickectAlertModel.m
// WXReader
//
// Created by LL on 2020/6/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_TickectAlertModel.h"
@implementation WXYZ_TickectAlertModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{
@"items" : WXYZ_TickectAlertItemsModel.class
};
}
@end
@implementation WXYZ_TickectAlertItemsModel
@end
@@ -0,0 +1,31 @@
//
// WXYZ_BookReaderBottomBar.h
// WXReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WXYZ_BookReaderBottomBar : UIView
// 正在自动阅读
@property (nonatomic, assign) BOOL autoReading;
// 显示工具栏
- (void)showToolBar;
// 隐藏工具栏
- (void)hiddenToolBar;
// 显示底部菜单按钮
- (void)showMenuView;
// 显示自动阅读栏
- (void)showAutoReadToolBar;
// 停止自动阅读
- (void)stopAutoRead;
@end
@@ -0,0 +1,426 @@
//
// WXYZ_BookReaderBottomBar.m
// TFReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_BookReaderBottomBar.h"
#import "TFSliderView.h"
#import "WXYZ_BookReaderMenuBar.h"
#import "WXYZ_BookReaderBottomSettingBar.h"
#import "TFReaderSettingHelper.h"
#import "TFReaderBookManager.h"
#import "AppDelegate.h"
#import "TFWebViewController.h"
#define ToolBar_Normal_Height (60 + PUB_TABBAR_OFFSET)
#define ToolBarSettingView_Height ((50 * 4) + kHalfMargin)
#define ToolBarAutoReadView_Height (ToolBar_Normal_Height + 20 + kMargin)
#define ToolBar_Large_Height (ToolBar_Normal_Height + ToolBarSettingView_Height)
#define animateDuration 0.2f
@interface WXYZ_BookReaderBottomBar () <TFSliderViewDelegate>
{
// 菜单按钮
UIView *menuView;
// 菜单栏设置背景
WXYZ_BookReaderBottomSettingBar *settingBackView;
// 自动阅读按钮
TFButton *autoReadButton;
// 分割线
UIView *grayLine;
// 亮度滑块
TFSliderView *brightnessSlider;
// 阅读速度滑块
TFSliderView *autoReadSpeedSlider;
// 夜间模式
UIButton *nightModeButton;
TFReaderSettingHelper *functionalManager;
TFButton *directoryButton;
TFButton *brightnessButton;
TFButton *fontSetButton;
#if TF_Comments_Mode
TFButton *commentButton;
#endif
}
@end
@implementation WXYZ_BookReaderBottomBar
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self initialize];
[self createSubViews];
}
return self;
}
- (void)initialize
{
self.backgroundColor = [UIColor whiteColor];
functionalManager = [TFReaderSettingHelper sharedManager];
}
- (void)createSubViews
{
UIImageView *topLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, - 10, self.width, 10)];
topLine.image = [UIImage imageNamed:@"tapbar_top_line"];
topLine.userInteractionEnabled = YES;
[self addSubview:topLine];
menuView = [[UIView alloc] init];
menuView.backgroundColor = [UIColor whiteColor];
[self addSubview:menuView];
[menuView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.bottom.mas_equalTo(self.mas_bottom).offset(- PUB_TABBAR_OFFSET);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(ToolBar_Normal_Height - PUB_TABBAR_OFFSET);
}];
#pragma mark - 目录按钮
directoryButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"目录") buttonImageName:@"book_menu_directory" buttonIndicator:TFButtonIndicatorTitleBottom];
directoryButton.tag = 0;
directoryButton.graphicDistance = 5;
directoryButton.buttonImageScale = 0.5;
[directoryButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:directoryButton];
#pragma mark - 亮度
brightnessButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"亮度") buttonImageName:@"book_menu_brightness_higher" buttonIndicator:TFButtonIndicatorTitleBottom];
brightnessButton.tag = 1;
brightnessButton.graphicDistance = 5;
brightnessButton.buttonImageScale = 0.5;
[brightnessButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:brightnessButton];
#pragma mark - 字体设置
fontSetButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"设置") buttonImageName:@"book_menu_setting" buttonIndicator:TFButtonIndicatorTitleBottom];
fontSetButton.tag = 2;
fontSetButton.graphicDistance = 5.5;
fontSetButton.buttonImageScale = 0.45;
[fontSetButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:fontSetButton];
#pragma mark - 评论
#if TF_Comments_Mode
commentButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"评论") buttonImageName:@"book_menu_comment_icon" buttonIndicator:TFButtonIndicatorTitleBottom];
commentButton.tag = 3;
commentButton.graphicDistance = 5;
commentButton.buttonImageScale = 0.45;
[commentButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:commentButton];
#endif
NSArray *buttonMenuArr = [NSArray arrayWithObjects:directoryButton, brightnessButton, fontSetButton,
#if TF_Comments_Mode
commentButton,
#endif
nil];
[buttonMenuArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedItemLength:(SCREEN_WIDTH / buttonMenuArr.count) leadSpacing:0 tailSpacing:0];
[buttonMenuArr mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(8);
make.height.mas_equalTo(menuView.mas_height).with.offset(- 16);
}];
#pragma mark - 亮度调节按钮
brightnessSlider = [[TFSliderView alloc] initWithFrame:CGRectMake(kMargin, kMargin, SCREEN_WIDTH - 2 * kMargin, ToolBar_Normal_Height - 2 * kMargin - PUB_TABBAR_OFFSET) sliderCutPointCount:1];
brightnessSlider.minimumValue = 0.01;
brightnessSlider.tag = 0;
brightnessSlider.hidden = YES;
brightnessSlider.sliderValue = [functionalManager getBrightness];
brightnessSlider.delegate = self;
brightnessSlider.minimumTintColor = kMainColor;
brightnessSlider.leftImageName = @"book_menu_brightness_lower";
brightnessSlider.rightImageName = @"book_menu_brightness_higher";
[self addSubview:brightnessSlider];
#pragma mark - 菜单栏设置背景
settingBackView = [[WXYZ_BookReaderBottomSettingBar alloc] initWithFrame:CGRectMake(0, 0, self.width, ToolBarSettingView_Height)];
settingBackView.hidden = YES;
[self addSubview:settingBackView];
#pragma mark - 自动阅读按钮
autoReadButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"开启自动阅读") buttonImageName:@"book_menu_auto_read_icon" buttonIndicator:TFButtonIndicatorTitleRight];
autoReadButton.graphicDistance = 0;
autoReadButton.buttonImageScale = 0.4;
autoReadButton.hidden = YES;
autoReadButton.buttonTintColor = kBlackColor;
[autoReadButton addTarget:self action:@selector(autoReadButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:autoReadButton];
[autoReadButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.mas_bottom).with.offset(- PUB_TABBAR_OFFSET);
make.centerX.mas_equalTo(settingBackView.mas_centerX);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(45);
}];
// 横线
grayLine = [[UIView alloc] init];
grayLine.hidden = YES;
grayLine.backgroundColor = kColorRGBA(247, 247, 247, 1);
[self addSubview:grayLine];
[grayLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.bottom.mas_equalTo(autoReadButton.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(5);
}];
#pragma mark - 阅读速度调节
autoReadSpeedSlider = [[TFSliderView alloc] initWithFrame:CGRectMake(kMargin, kHalfMargin, SCREEN_WIDTH - 2 * kMargin, 30) sliderCutPointCount:10];
autoReadSpeedSlider.tag = 1;
autoReadSpeedSlider.hidden = YES;
autoReadSpeedSlider.stepSlider = YES;
autoReadSpeedSlider.delegate = self;
autoReadSpeedSlider.invertedValue = YES;
autoReadSpeedSlider.sliderValue = 10 - [functionalManager getReadSpeed] / 5;
autoReadSpeedSlider.leftImageName = @"book_menu_auto_read_slow";
autoReadSpeedSlider.rightImageName = @"book_menu_auto_read_fast";
[self addSubview:autoReadSpeedSlider];
nightModeButton = [UIButton buttonWithType:UIButtonTypeCustom];
nightModeButton.tag = 10000;
nightModeButton.adjustsImageWhenHighlighted = NO;
nightModeButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
nightModeButton.contentHorizontalAlignment = UIControlContentVerticalAlignmentFill;
if ([functionalManager getNightModeState] == TFReaderPatternModeNight) {
[nightModeButton setImage:[UIImage imageNamed:@"book_menu_reader_night"] forState:UIControlStateNormal];
} else {
[nightModeButton setImage:[UIImage imageNamed:@"book_menu_reader_day"] forState:UIControlStateNormal];
}
[nightModeButton addTarget:self action:@selector(nightModeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:nightModeButton];
[nightModeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(40);
make.right.mas_equalTo(self.mas_right).with.offset(- kMargin);
make.bottom.mas_equalTo(menuView.mas_top).with.offset(- kMargin);
}];
}
- (void)reloadTabbar
{
[self removeAllSubviews];
[self createSubViews];
}
// 菜单栏按钮点击
- (void)toolBarButtonClick:(UIButton *)sender
{
switch (sender.tag) {
case 0:// 目录
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@"WXBookDirectoryViewController"];
[self hiddenToolBar];
break;
case 1:// 亮度
brightnessSlider.hidden = NO;
break;
case 2:// 设置
settingBackView.hidden = NO;
[self showLargeToolBar];
break;
case 3:// 评论
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@"TFCommentsViewController"];
[self hiddenToolBar];
break;
default:
break;
}
[self hiddenMenuView];
}
// 显示底部菜单按钮
- (void)showMenuView
{
menuView.hidden = NO;
}
// 隐藏底部菜单按钮
- (void)hiddenMenuView
{
[self hiddenNavBar];
menuView.hidden = YES;
}
// 夜间模式
- (void)nightModeClick:(UIButton *)sender
{
if ([functionalManager getNightModeState] == TFReaderPatternModeNight) {
[functionalManager setNightModeState:TFReaderPatternModeDaytime];
[sender setImage:[UIImage imageNamed:@"book_menu_reader_day"] forState:UIControlStateNormal];
} else {
[functionalManager setNightModeState:TFReaderPatternModeNight];
[sender setImage:[UIImage imageNamed:@"book_menu_reader_night"] forState:UIControlStateNormal];
}
[[WXYZ_BookReaderMenuBar sharedManager] hiddend];
}
// 隐藏导航栏
- (void)hiddenNavBar
{
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_ToolNav object:nil];
}
// 显示工具栏
- (void)showToolBar
{
self.hidden = NO;
menuView.hidden = NO;
if ([functionalManager getNightModeState] == TFReaderPatternModeNight) {
[nightModeButton setImage:[UIImage imageNamed:@"book_menu_reader_night"] forState:UIControlStateNormal];
} else {
[nightModeButton setImage:[UIImage imageNamed:@"book_menu_reader_day"] forState:UIControlStateNormal];
}
[UIView animateWithDuration:animateDuration animations:^{
self.frame = CGRectMake(0, SCREEN_HEIGHT - ToolBar_Normal_Height, SCREEN_WIDTH, ToolBar_Normal_Height);
self->nightModeButton.alpha = 1;
} completion:^(BOOL finished) {
}];
autoReadButton.buttonTitle = TFLocalizedString(@"开启自动阅读");
[autoReadButton setNeedsLayout];
[autoReadButton layoutIfNeeded];
directoryButton.buttonTitle = TFLocalizedString(@"目录");
brightnessButton.buttonTitle = TFLocalizedString(@"亮度");
fontSetButton.buttonTitle = TFLocalizedString(@"设置");
commentButton.buttonTitle = TFLocalizedString(@"评论");
}
// 显示自动阅读栏
- (void)showAutoReadToolBar
{
nightModeButton.alpha = 0;
self.hidden = NO;
[UIView animateWithDuration:animateDuration animations:^{
self.frame = CGRectMake(0, SCREEN_HEIGHT - ToolBarAutoReadView_Height, SCREEN_WIDTH, ToolBarAutoReadView_Height);
} completion:^(BOOL finished) {
self->autoReadButton.hidden = NO;
self->autoReadSpeedSlider.hidden = NO;
self->settingBackView.hidden = YES;
self->grayLine.hidden = NO;
}];
}
// 显示多选工具栏
- (void)showLargeToolBar
{
nightModeButton.alpha = 0;
[UIView animateWithDuration:animateDuration animations:^{
self.frame = CGRectMake(0, SCREEN_HEIGHT - ToolBar_Large_Height, SCREEN_WIDTH, ToolBar_Large_Height);
} completion:^(BOOL finished) {
self->grayLine.hidden = NO;
self->autoReadButton.hidden = NO;
}];
}
// 隐藏工具栏
- (void)hiddenToolBar
{
brightnessSlider.hidden = YES;
settingBackView.hidden = YES;
grayLine.hidden = YES;
autoReadButton.hidden = YES;
autoReadSpeedSlider.hidden = YES;
if (_autoReading && functionalManager.state == TFReaderAutoReadStatePause) {
[functionalManager setAutoReaderState:TFReaderAutoReadStateResume];
}
[UIView animateWithDuration:animateDuration animations:^{
self.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, ToolBar_Normal_Height);
self->nightModeButton.alpha = 0;
} completion:^(BOOL finished) {
self.hidden = YES;
}];
}
#pragma mark - 按钮点击事件
- (void)sliderValueEndChanged:(CGFloat)endValue slider:(TFSliderView *)sender
{
// 设置亮度
if (sender.tag == 0) {
[functionalManager setBrightness:endValue];
} else {// 设置阅读速度
[functionalManager setReadSpeed:(NSInteger)((endValue + 1) * 5)];
}
}
// 关闭自动阅读
- (void)stopAutoRead
{
if (_autoReading) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"自动阅读已关闭")];
}
_autoReading = NO;
[functionalManager setAutoReaderState:TFReaderAutoReadStateStop];
autoReadButton.buttonImageName = @"book_menu_auto_read_icon";
autoReadButton.buttonTitle = TFLocalizedString(@"开启自动阅读");
autoReadButton.buttonTintColor = kBlackColor;
[self hiddenToolBar];
[self hiddenNavBar];
[[WXYZ_BookReaderMenuBar sharedManager] hiddend];
}
// 自动阅读
- (void)autoReadButtonClick
{
if (_autoReading) {
[self stopAutoRead];
} else {
_autoReading = YES;
autoReadButton.buttonImageName = @"book_menu_auto_read_exit";
autoReadButton.buttonTitle = TFLocalizedString(@"关闭自动阅读");
autoReadButton.buttonTintColor = [UIColor colorWithRed: 241.0/255.0 green: 83.0/255.0 blue: 29.0/255.0 alpha: 1.0];
[functionalManager setAutoReaderState:TFReaderAutoReadStateStart];
[self hiddenToolBar];
[self hiddenNavBar];
[[WXYZ_BookReaderMenuBar sharedManager] hiddend];
}
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if (view == nil) {
// 超出父视图的按钮tag值为10000
CGPoint tempoint = [[self viewWithTag:10000] convertPoint:point fromView:self];
if (CGRectContainsPoint([self viewWithTag:10000].bounds, tempoint)) {
view = [self viewWithTag:10000];
}
}
return view;
}
@end
@@ -0,0 +1,13 @@
//
// WXYZ_BookReaderBottomSettingBar.h
// WXReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WXYZ_BookReaderBottomSettingBar : UIView
@end
@@ -0,0 +1,522 @@
//
// WXYZ_BookReaderBottomSettingBar.m
// TFReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_BookReaderBottomSettingBar.h"
#import "TFReaderSettingHelper.h"
#define ToolBarSettingView_Height ((50 * 4) + kHalfMargin)
@implementation WXYZ_BookReaderBottomSettingBar
{
// 字号显示
UILabel *fontSizeLabel;
UIButton *decreaseFontBtn;
UIButton *increaseFontBtn;
TFReaderSettingHelper *functionalManager;
UIScrollView *backgroundScorll;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor whiteColor];
functionalManager = [TFReaderSettingHelper sharedManager];
[self createSubViews];
}
return self;
}
- (void)createSubViews
{
CGFloat titleHeight = 50;
CGFloat titleWidth = 50;
CGFloat factoryButtonWidth = (SCREEN_WIDTH - titleWidth - 6 * kHalfMargin) / 4;
CGFloat factoryButtonHeight = 30;
#pragma mark - 字号
UILabel *fontTitle = [[UILabel alloc] init];
fontTitle.text = TFLocalizedString(@"字号");
fontTitle.textAlignment = NSTextAlignmentCenter;
fontTitle.textColor = kGrayTextColor;
fontTitle.font = kFont13;
[self addSubview:fontTitle];
[fontTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(self.mas_top).with.offset(kHalfMargin);
make.width.mas_equalTo(titleWidth);
make.height.mas_equalTo(titleHeight);
}];
#pragma mark - 字号减小
decreaseFontBtn = [self factorySettingButtonWithBackViewImageName:@"book_menu_font_sub" buttonTitle:nil tag:0 fitImageView:YES];
decreaseFontBtn.adjustsImageWhenHighlighted = NO;
[decreaseFontBtn addTarget:self action:@selector(fontSizeChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[decreaseFontBtn addTarget:self action:@selector(fontSizeChangeHighlighted:) forControlEvents:UIControlEventTouchDown];
[self addSubview:decreaseFontBtn];
[decreaseFontBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(fontTitle.mas_right).with.offset(kHalfMargin);
make.centerY.mas_equalTo(fontTitle.mas_centerY);
make.width.mas_equalTo(factoryButtonWidth);
make.height.mas_equalTo(factoryButtonHeight);
}];
#pragma mark - 字号增加
increaseFontBtn = [self factorySettingButtonWithBackViewImageName:@"book_menu_font_add" buttonTitle:nil tag:1 fitImageView:YES];
increaseFontBtn.adjustsImageWhenHighlighted = NO;
[increaseFontBtn addTarget:self action:@selector(fontSizeChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[increaseFontBtn addTarget:self action:@selector(fontSizeChangeHighlighted:) forControlEvents:UIControlEventTouchDown];
[self addSubview:increaseFontBtn];
[increaseFontBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(decreaseFontBtn.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
if ([functionalManager getReaderFontSize] == [functionalManager getReaderMinFontSize]) {
decreaseFontBtn.imageView.tintColor = kGrayTextColor;
} else if ([functionalManager getReaderFontSize] == [functionalManager getReaderMaxFontSize]) {
increaseFontBtn.imageView.tintColor = kGrayTextColor;
}
#pragma mark - 显示字号
fontSizeLabel = [[UILabel alloc] init];
fontSizeLabel.textAlignment = NSTextAlignmentCenter;
fontSizeLabel.font = kFont15;
fontSizeLabel.text = [NSString stringWithFormat:@"%.lf",[functionalManager getReaderFontSize]];
fontSizeLabel.textColor = kBlackColor;
[self addSubview:fontSizeLabel];
[fontSizeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(decreaseFontBtn.mas_right);
make.right.mas_equalTo(increaseFontBtn.mas_left);
make.centerY.mas_equalTo(decreaseFontBtn.mas_centerY);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 字体间距
UILabel *spaceLineTitle = [[UILabel alloc] init];
spaceLineTitle.text = TFLocalizedString(@"间距");
spaceLineTitle.textAlignment = NSTextAlignmentCenter;
spaceLineTitle.textColor = kGrayTextColor;
spaceLineTitle.font = kFont13;
[self addSubview:spaceLineTitle];
[spaceLineTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(fontTitle.mas_bottom);
make.width.mas_equalTo(titleWidth);
make.height.mas_equalTo(titleHeight);
}];
#pragma mark - 字体间距大
UIButton *lineSpacingSmall = [self factorySettingButtonWithBackViewImageName:@"book_menu_line_spacing_big" buttonTitle:nil tag:10 fitImageView:YES];
[lineSpacingSmall addTarget:self action:@selector(lineSpacingChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:lineSpacingSmall];
[lineSpacingSmall mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(decreaseFontBtn.mas_left);
make.centerY.mas_equalTo(spaceLineTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 字体间距中
UIButton *lineSpacingMedium = [self factorySettingButtonWithBackViewImageName:@"book_menu_line_spacing_medium" buttonTitle:nil tag:11 fitImageView:YES];
[lineSpacingMedium addTarget:self action:@selector(lineSpacingChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:lineSpacingMedium];
[lineSpacingMedium mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(fontSizeLabel.mas_centerX);
make.centerY.mas_equalTo(spaceLineTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 字体间距小
UIButton *lineSpacingBig = [self factorySettingButtonWithBackViewImageName:@"book_menu_line_spacing_small" buttonTitle:nil tag:12 fitImageView:YES];
[lineSpacingBig addTarget:self action:@selector(lineSpacingChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:lineSpacingBig];
[lineSpacingBig mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(spaceLineTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
CGFloat t_lineSpacing = [functionalManager getReaderLinesSpacing];
if (t_lineSpacing == line_spacing_small) {
lineSpacingSmall.backgroundColor = kMainColor;
lineSpacingSmall.imageView.tintColor = kWhiteColor;
} else if (t_lineSpacing == line_spacing_medium) {
lineSpacingMedium.backgroundColor = kMainColor;
lineSpacingMedium.imageView.tintColor = kWhiteColor;
} else {
lineSpacingBig.backgroundColor = kMainColor;
lineSpacingBig.imageView.tintColor = kWhiteColor;
}
#pragma mark - 翻页
UILabel *pageTitle = [[UILabel alloc] init];
pageTitle.text = TFLocalizedString(@"翻页");
pageTitle.textAlignment = NSTextAlignmentCenter;
pageTitle.textColor = kGrayTextColor;
pageTitle.font = kFont13;
[self addSubview:pageTitle];
[pageTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(spaceLineTitle.mas_bottom);
make.width.mas_equalTo(titleWidth);
make.height.mas_equalTo(titleHeight);
}];
#pragma mark - 仿真
UIButton *pageCurlButton = [self factorySettingButtonWithBackViewImageName:nil buttonTitle:TFLocalizedString(@"仿真") tag:100 fitImageView:YES];
[pageCurlButton addTarget:self action:@selector(transitionStyleChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:pageCurlButton];
[pageCurlButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(decreaseFontBtn.mas_left);
make.centerY.mas_equalTo(pageTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 滚动
UIButton *scrollButton = [self factorySettingButtonWithBackViewImageName:nil buttonTitle:TFLocalizedString(@"滑动") tag:101 fitImageView:YES];
[scrollButton addTarget:self action:@selector(transitionStyleChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:scrollButton];
[scrollButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(pageCurlButton.mas_right).with.offset(7);
make.centerY.mas_equalTo(pageTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 覆盖
UIButton *coverButton = [self factorySettingButtonWithBackViewImageName:nil buttonTitle:TFLocalizedString(@"覆盖") tag:102 fitImageView:YES];
[coverButton addTarget:self action:@selector(transitionStyleChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:coverButton];
[coverButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(scrollButton.mas_right).with.offset(7);
make.centerY.mas_equalTo(pageTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
#pragma mark - 无效果
UIButton *noneButton = [self factorySettingButtonWithBackViewImageName:nil buttonTitle:TFLocalizedString(@"") tag:103 fitImageView:YES];
[noneButton addTarget:self action:@selector(transitionStyleChangeClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:noneButton];
[noneButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(coverButton.mas_right).with.offset(7);
make.centerY.mas_equalTo(pageTitle.mas_centerY);
make.width.mas_equalTo(decreaseFontBtn.mas_width);
make.height.mas_equalTo(decreaseFontBtn.mas_height);
}];
switch ([functionalManager getTransitionStyle]) {
case TFReaderTransitionStylePageCurl:
pageCurlButton.selected = YES;
pageCurlButton.backgroundColor = kMainColor;
break;
case TFReaderTransitionStyleScroll:
scrollButton.selected = YES;
scrollButton.backgroundColor = kMainColor;
break;
case TFReaderTransitionStyleCover:
coverButton.selected = YES;
coverButton.backgroundColor = kMainColor;
break;
case TFReaderTransitionStyleNone:
noneButton.selected = YES;
noneButton.backgroundColor = kMainColor;
break;
default:
break;
}
#pragma mark - 背景
UILabel *backViewTitle = [[UILabel alloc] init];
backViewTitle.text = TFLocalizedString(@"背景");
backViewTitle.textAlignment = NSTextAlignmentCenter;
backViewTitle.textColor = kGrayTextColor;
backViewTitle.font = kFont13;
[self addSubview:backViewTitle];
[backViewTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(pageTitle.mas_bottom);
make.width.mas_equalTo(titleWidth);
make.height.mas_equalTo(titleHeight);
}];
#pragma mark - 背景滚动
backgroundScorll = [[UIScrollView alloc] init];
backgroundScorll.backgroundColor = kWhiteColor;
backgroundScorll.showsVerticalScrollIndicator = NO;
backgroundScorll.showsHorizontalScrollIndicator = NO;
[self addSubview:backgroundScorll];
[backgroundScorll mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(decreaseFontBtn.mas_left);
make.right.mas_equalTo(self.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(backViewTitle.mas_centerY);
make.height.mas_equalTo(backViewTitle.mas_height);
}];
[backgroundScorll setNeedsLayout];
[backgroundScorll layoutIfNeeded];
NSMutableArray *backgroundImageArr = [[functionalManager getReaderBackgroundColorModeArray] mutableCopy];
[backgroundImageArr removeLastObject];
NSUInteger buttonNum = backgroundImageArr.count;//每行多少按钮
CGFloat button_W = factoryButtonHeight + 5; //按钮宽
CGFloat button_H = factoryButtonHeight + 5; //按钮高
CGFloat space_X = (CGRectGetWidth(backgroundScorll.bounds) - (button_W * buttonNum)) / (buttonNum - 1);// 按钮间距
for (int i = 0; i < backgroundImageArr.count; i++) {
int loc = i % buttonNum;//列号
CGFloat button_X = (space_X + button_W) * loc;
UIButton *button = [self factorySettingButtonWithBackViewImageName:@"" buttonTitle:nil tag:i fitImageView:NO];
button.tintColor = kMainColor;
button.layer.contents = (id)[UIImage imageNamed:[[functionalManager getReaderBackgroundColorModeArray] objectAtIndex:i]].CGImage;
button.layer.cornerRadius = 4;
button.clipsToBounds = YES;
button.tag = i;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.contentHorizontalAlignment = UIControlContentVerticalAlignmentFill;
[button setImageEdgeInsets:UIEdgeInsetsMake(factoryButtonHeight * 0.5, factoryButtonHeight * 0.5, 0, 0)];
[button addTarget:self action:@selector(changeBackgroundImageClick:) forControlEvents:UIControlEventTouchUpInside];
[backgroundScorll addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(button_X);
make.centerY.mas_equalTo(backgroundScorll.mas_centerY);
make.width.mas_equalTo(button_W);
make.height.mas_equalTo(button_H);
}];
if (i == TFReaderBackColorWhite) {
button.layer.borderColor = kColorRGBA(235, 235, 241, 1).CGColor;
button.layer.borderWidth = 0.8;
}
if ([functionalManager getReaderBackgroundColorMode] == i) {
[button setImage:[[UIImage imageNamed:@"book_setting_select"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
}
}
backgroundScorll.contentSize = CGSizeMake((button_W + kHalfMargin) * backgroundImageArr.count, 0);
[[NSNotificationCenter defaultCenter] addObserverForName:Notification_Switch_Language object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
fontTitle.text = TFLocalizedString(@"字号");
spaceLineTitle.text = TFLocalizedString(@"间距");
pageTitle.text = TFLocalizedString(@"翻页");
pageCurlButton.titleLabel.text = TFLocalizedString(@"仿真");
[pageCurlButton setTitle:TFLocalizedString(@"仿真") forState:UIControlStateNormal];
scrollButton.titleLabel.text = TFLocalizedString(@"滑动");
[scrollButton setTitle:TFLocalizedString(@"滑动") forState:UIControlStateNormal];
coverButton.titleLabel.text = TFLocalizedString(@"覆盖");
[coverButton setTitle:TFLocalizedString(@"覆盖") forState:UIControlStateNormal];
noneButton.titleLabel.text = TFLocalizedString(@"");
[noneButton setTitle:TFLocalizedString(@"") forState:UIControlStateNormal];
backViewTitle.text = TFLocalizedString(@"背景");
}];
}
#pragma mark - 点击事件
// 改变字号
- (void)fontSizeChangeClick:(UIButton *)sender
{
sender.backgroundColor = kColorRGBA(235, 235, 241, 1);
sender.imageView.tintColor = kBlackColor;
CGFloat temp_font = [functionalManager getReaderFontSize];
if (sender.tag == 0) {
if (temp_font == [functionalManager getReaderMinFontSize]) {
sender.imageView.tintColor = kGrayTextColor;
return;
}
[functionalManager setReaderFontSize:temp_font - 1];
fontSizeLabel.text = [NSString stringWithFormat:@"%.lf",[functionalManager getReaderFontSize]];
} else {
if (temp_font == [functionalManager getReaderMaxFontSize]) {
sender.imageView.tintColor = kGrayTextColor;
return;
}
[functionalManager setReaderFontSize:temp_font + 1];
fontSizeLabel.text = [NSString stringWithFormat:@"%.lf",[functionalManager getReaderFontSize]];
}
if ([functionalManager getReaderFontSize] == [functionalManager getReaderMinFontSize]) {
decreaseFontBtn.imageView.tintColor = kGrayTextColor;
} else if ([functionalManager getReaderFontSize] == [functionalManager getReaderMaxFontSize]) {
increaseFontBtn.imageView.tintColor = kGrayTextColor;
} else {
decreaseFontBtn.imageView.tintColor = kBlackColor;
increaseFontBtn.imageView.tintColor = kBlackColor;
}
}
- (void)fontSizeChangeHighlighted:(UIButton *)sender
{
if (sender.tag == 0 && [functionalManager getReaderFontSize] == [functionalManager getReaderMinFontSize]) {
return;
}
if (sender.tag == 1 && [functionalManager getReaderFontSize] == [functionalManager getReaderMaxFontSize]) {
return;
}
sender.backgroundColor = kMainColor;
sender.imageView.tintColor = kWhiteColor;
}
// 改变背景色
- (void)changeBackgroundImageClick:(UIButton *)sender
{
[backgroundScorll.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[UIButton class]]) {
UIButton *t_btn = (UIButton *)obj;
[t_btn setImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];
}
}];
[sender setImage:[[UIImage imageNamed:@"book_setting_select"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[functionalManager setNightModeState:TFReaderPatternModeDaytime];
[functionalManager setReaderBackgroundColor:sender.tag];
}
// 设置翻页类型
- (void)transitionStyleChangeClick:(UIButton *)sender
{
for (UIView *t_view in self.subviews) {
if ([t_view isKindOfClass:[UIButton class]] && (t_view.tag == 100 || t_view.tag == 101 || t_view.tag == 102 || t_view.tag == 103)) {
UIButton *t_button = (UIButton *)t_view;
t_button.backgroundColor = kColorRGBA(235, 235, 241, 1);
t_button.selected = NO;
}
}
switch (sender.tag) {
case 100:
[functionalManager setTransitionStyle:TFReaderTransitionStylePageCurl];
break;
case 101:
[functionalManager setTransitionStyle:TFReaderTransitionStyleScroll];
break;
case 102:
[functionalManager setTransitionStyle:TFReaderTransitionStyleCover];
break;
case 103:
[functionalManager setTransitionStyle:TFReaderTransitionStyleNone];
break;
default:
break;
}
sender.selected = YES;
sender.backgroundColor = kMainColor;
}
// 设置字间距
- (void)lineSpacingChangeClick:(UIButton *)sender
{
for (UIView *t_view in self.subviews) {
if ([t_view isKindOfClass:[UIButton class]] && (t_view.tag == 10 || t_view.tag == 11 || t_view.tag == 12)) {
UIButton *t_button = (UIButton *)t_view;
t_button.backgroundColor = kColorRGBA(235, 235, 241, 1);
t_button.imageView.tintColor = kBlackColor;
}
}
switch (sender.tag) {
case 10:
[functionalManager setReaderLinesSpacing:line_spacing_small];
break;
case 11:
[functionalManager setReaderLinesSpacing:line_spacing_medium];
break;
case 12:
[functionalManager setReaderLinesSpacing:line_spacing_big];
break;
default:
break;
}
sender.imageView.tintColor = kWhiteColor;
sender.backgroundColor = kMainColor;
}
- (UIButton *)factorySettingButtonWithBackViewImageName:(NSString *)imageName buttonTitle:(NSString *)title tag:(NSInteger)tag fitImageView:(BOOL)fitImage
{
UIButton *t_factory = [UIButton buttonWithType:UIButtonTypeCustom];
t_factory.backgroundColor = kColorRGBA(235, 235, 241, 1);
t_factory.layer.cornerRadius = 2;
t_factory.tag = tag;
[t_factory.titleLabel setTextAlignment:NSTextAlignmentCenter];
if (title.length > 0) {
t_factory.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[t_factory setTitle:title forState:0];
[t_factory.titleLabel setFont:kMainFont];
[t_factory setTitleColor:kBlackColor forState:UIControlStateNormal];
[t_factory setTitleColor:kWhiteColor forState:UIControlStateSelected];
} else {
if (imageName.length > 0) {
t_factory.imageView.tintColor = kBlackColor;
t_factory.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
t_factory.contentHorizontalAlignment = UIControlContentVerticalAlignmentFill;
[t_factory setImage:[[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[t_factory setImage:[[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateHighlighted];
}
if (fitImage) {
t_factory.imageView.contentMode = UIViewContentModeScaleAspectFit;
} else {
t_factory.imageView.tintColor = kMainColor;
}
}
return t_factory;
}
- (void)setHidden:(BOOL)hidden {
[super setHidden:hidden];
if (!hidden) {
[backgroundScorll.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[UIButton class]]) {
UIButton *t_btn = (UIButton *)obj;
if ([functionalManager getReaderBackgroundColorMode] == t_btn.tag) {
[t_btn setImage:[UIImage imageNamed:@"book_setting_select"] forState:UIControlStateNormal];
} else {
[t_btn setImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];
}
}
}];
}
}
@end
@@ -0,0 +1,21 @@
//
// WXBookReaderToolBar.h
// WXReader
//
// Created by Andrew on 2018/5/30.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WXYZ_BookReaderMenuBar : UIView
interface_singleton
- (void)hiddend;
- (void)show;
- (void)stopAutoRead;
@end
@@ -0,0 +1,131 @@
//
// WXBookReaderToolBar.m
// TFReader
//
// Created by Andrew on 2018/5/30.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_BookReaderMenuBar.h"
#import "TFReaderSettingHelper.h"
#import "WXYZ_BookReaderTopBar.h"
#import "WXYZ_BookReaderBottomBar.h"
#if TF_Enable_Ai
#import "WXYZ_TouchAssistantView.h"
#endif
#define ToolBar_Normal_Height (60 + PUB_TABBAR_OFFSET)
@interface WXYZ_BookReaderMenuBar ()
{
// 导航条
WXYZ_BookReaderTopBar *navBar;
// 工具条
WXYZ_BookReaderBottomBar *toolBar;
TFReaderSettingHelper *functionalManager;
}
@end
@implementation WXYZ_BookReaderMenuBar
implementation_singleton(WXYZ_BookReaderMenuBar)
- (instancetype)init
{
if (self = [super init]) {
[self initialize];
[self createSubViews];
}
return self;
}
- (void)initialize
{
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
self.backgroundColor = [UIColor clearColor];
[kMainWindow addSubview:self];
self.hidden = YES;
functionalManager = [TFReaderSettingHelper sharedManager];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hiddend) name:NSNotification_Hidden_Bottom_ToolNav object:nil];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint toolBarPoint = [toolBar.layer convertPoint:[touch locationInView:self] fromLayer:self.layer];
CGPoint navBarPoint = [navBar.layer convertPoint:[touch locationInView:self] fromLayer:self.layer];
if (![toolBar.layer containsPoint:toolBarPoint] && ![navBar.layer containsPoint:navBarPoint]) {
[self hiddend];
}
}
- (void)hiddend
{
if (functionalManager.state == TFReaderAutoReadStateStart && self.hidden) {
[self show];
return;
}
[navBar hiddenNavBarCompletion:^{
self.hidden = YES;
}];
[toolBar hiddenToolBar];
#if TF_Enable_Ai
[[WXYZ_TouchAssistantView sharedManager] hiddenAssistiveTouchView];
#endif
}
- (void)show
{
[kMainWindow bringSubviewToFront:self];
self.hidden = NO;
if (!toolBar.autoReading) {
[navBar showNavBarCompletion:^{
}];
[toolBar showToolBar];
} else {
[functionalManager setAutoReaderState:TFReaderAutoReadStatePause];
[navBar hiddenNavBarCompletion:^{
}];
[toolBar showAutoReadToolBar];
}
#if TF_Enable_Ai
[[WXYZ_TouchAssistantView sharedManager] showAssistiveTouchView];
#endif
}
- (void)createSubViews
{
navBar = [[WXYZ_BookReaderTopBar alloc] initWithFrame:CGRectMake(0, - PUB_NAVBAR_HEIGHT, SCREEN_WIDTH, PUB_NAVBAR_HEIGHT)];
[self addSubview:navBar];
toolBar = [[WXYZ_BookReaderBottomBar alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, ToolBar_Normal_Height)];
[self addSubview:toolBar];
}
- (void)stopAutoRead
{
[toolBar stopAutoRead];
}
- (void)popViewContriller
{
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Back object:nil];
[self stopAutoRead];
}
@end
@@ -0,0 +1,13 @@
//
// WXYZ_BookReaderMenuPayView.h
// WXReader
//
// Created by Andrew on 2018/7/15.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WXYZ_BookReaderMenuPayView : UIView
@end
@@ -0,0 +1,167 @@
//
// WXYZ_BookReaderMenuPayView.m
// WXReader
//
// Created by Andrew on 2018/7/15.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_BookReaderMenuPayView.h"
#import "TFRechargeViewController.h"
#import "WXYZ_ChapterBottomPayBar.h"
#import "TFReaderSettingHelper.h"
#import "TFReaderBookManager.h"
@interface WXYZ_BookReaderMenuPayView ()
{
TFReaderSettingHelper *functionalManager;
}
@end
@implementation WXYZ_BookReaderMenuPayView
- (instancetype)init
{
if (self = [super init]) {
[self initialize];
[self createSubViews];
}
return self;
}
- (void)initialize
{
self.frame = CGRectMake(0, SCREEN_HEIGHT / 2 - PUB_TABBAR_OFFSET - 2 * kMargin, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
self.backgroundColor = [UIColor clearColor];
functionalManager = [TFReaderSettingHelper sharedManager];
}
- (void)createSubViews
{
UIButton *buyBulkButton = [UIButton buttonWithType:UIButtonTypeCustom];
buyBulkButton.layer.cornerRadius = 4;
buyBulkButton.layer.borderColor = [functionalManager getReaderTextColor].CGColor;
buyBulkButton.layer.borderWidth = 0.7;
buyBulkButton.clipsToBounds = YES;
[buyBulkButton setTitle:TFLocalizedString(@"批量购买更优惠") forState:UIControlStateNormal];
[buyBulkButton setTitleColor:[functionalManager getReaderTextColor] forState:UIControlStateNormal];
[buyBulkButton.titleLabel setFont:kMainFont];
[buyBulkButton addTarget:self action:@selector(buyBulkButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:buyBulkButton];
[buyBulkButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.mas_bottom).with.offset(- 2 * kMargin);
make.left.mas_equalTo(self.mas_left).with.offset(2 * kMargin);
make.right.mas_equalTo(self.mas_right).with.offset(- 2 * kMargin);
make.height.mas_equalTo(40);
}];
UIButton *buyButton = [UIButton buttonWithType:UIButtonTypeCustom];
buyButton.layer.cornerRadius = 4;
buyButton.layer.borderColor = [functionalManager getReaderTextColor].CGColor;
buyButton.layer.borderWidth = 0.7;
buyButton.clipsToBounds = YES;
[buyButton setTitle:TFLocalizedString(@"确定购买") forState:UIControlStateNormal];
[buyButton setTitleColor:[functionalManager getReaderTextColor] forState:UIControlStateNormal];
[buyButton.titleLabel setFont:kMainFont];
[buyButton addTarget:self action:@selector(buyCurrentChapter) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:buyButton];
[buyButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(buyBulkButton.mas_top).with.offset(- 15);
make.left.mas_equalTo(buyBulkButton.mas_left);
make.right.mas_equalTo(buyBulkButton.mas_right);
make.height.mas_equalTo(buyBulkButton.mas_height);
}];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.text = TFLocalizedString(@"支持正版");
titleLabel.textColor = [functionalManager getReaderTextColor];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.font = kFont10;
titleLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:titleLabel];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.mas_centerX);
make.bottom.mas_equalTo(buyButton.mas_top).with.offset( - 2 * kMargin);
make.width.mas_equalTo(100);
make.height.mas_equalTo(20);
}];
UIView *leftLine = [[UIView alloc] init];
leftLine.backgroundColor = [functionalManager getReaderTextColor];
[self addSubview:leftLine];
[leftLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(titleLabel.mas_centerY);
make.left.mas_equalTo(buyBulkButton.mas_left);
make.right.mas_equalTo(titleLabel.mas_left).with.offset(- kHalfMargin);
make.height.mas_equalTo(kCellLineHeight);
}];
UIView *rightLine = [[UIView alloc] init];
rightLine.backgroundColor = [functionalManager getReaderTextColor];
[self addSubview:rightLine];
[rightLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(titleLabel.mas_centerY);
make.left.mas_equalTo(titleLabel.mas_right).with.offset(kHalfMargin);
make.right.mas_equalTo(buyBulkButton.mas_right);
make.height.mas_equalTo(kCellLineHeight);
}];
}
- (void)buyBulkButtonClick
{
TFReaderBookManager *bookManager = [TFReaderBookManager sharedManager];
TFProductionChapterModel *t_model = [[TFProductionChapterModel alloc] init];
t_model.production_id = bookManager.book_id;
t_model.chapter_id = bookManager.chapter_id;
WXYZ_ChapterBottomPayBar *payBar = [[WXYZ_ChapterBottomPayBar alloc] initWithChapterModel:t_model barType:WXYZ_BottomPayBarTypeBuyChapter productionType:TFProductionTypeNovel];
[payBar showBottomPayBar];
}
- (void)buyCurrentChapter
{
if (!TFUserInfoManager.isLogin) {
[TFLoginOptionsViewController presentLoginView:nil];
return;
}
TFReaderBookManager *bookManager = [TFReaderBookManager sharedManager];
TFProductionChapterModel *t_model = [[TFProductionChapterModel alloc] init];
t_model.production_id = bookManager.book_id;
t_model.chapter_id = bookManager.chapter_id;
[TFNetworkTools POST:Book_Buy_Chapter parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:bookManager.book_id], @"chapter_id":[TFUtilsHelper formatStringWithInteger:bookManager.chapter_id], @"num":@"1"} model:nil success:^(BOOL isSuccess, id _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
NSArray<NSString *> *t_arr = [requestModel.data objectForKey:@"chapter_ids"];
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"购买成功")];
NSInteger index = [TFReaderBookManager sharedManager].currentChapterIndex;
[TFReaderBookManager sharedManager].bookModel.chapter_list[index].is_preview = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Retry_Chapter object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Production_Pay_Success object:t_arr];
} else if (requestModel.code == 802) {
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@"TFRechargeViewController"];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
}];
}
@end
@@ -0,0 +1,19 @@
//
// WXYZ_BookReaderTopBar.h
// WXReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WXYZ_BookReaderTopBar : UIView
// 显示导航条
- (void)showNavBarCompletion:(void(^)(void))completion;
// 隐藏导航条
- (void)hiddenNavBarCompletion:(void(^)(void))completion;
@end
@@ -0,0 +1,302 @@
//
// WXYZ_BookReaderTopBar.m
// TFReader
//
// Created by Andrew on 2018/6/12.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_BookReaderTopBar.h"
#import "TFReaderSettingHelper.h"
#import "TFReaderBookManager.h"
#import "TFShareManager.h"
#if TF_Download_Mode
#import "TFNovelDownloadMenuView.h"
#import "TFReaderBookManager.h"
#endif
#if TF_Enable_Ai
#import "WXYZ_BookAiPlayPageViewController.h"
#import "TFAudioPlayViewController.h"
#import "WXYZ_AudioSettingHelper.h"
#endif
#import "TFReadRecordManager.h"
#import "WXYZ_MoreView.h"
#import "WXYZ_GiftView.h"
#import "AppDelegate.h"
@interface WXYZ_BookReaderTopBar ()
@property (nonatomic, assign) BOOL navBarShowing;
@property (nonatomic, strong) NSMutableArray<UIButton *> *buttonMenuArr;
@property (nonatomic, strong) UIButton *radioButton;
@end
@implementation WXYZ_BookReaderTopBar
{
TFReaderSettingHelper *functionalManager;
UIButton *moreButton;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self initialize];
[self createSubViews];
}
return self;
}
- (void)initialize
{
self.backgroundColor = [UIColor whiteColor];
functionalManager = [TFReaderSettingHelper sharedManager];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hiddenNavBar) name:NSNotification_Hidden_ToolNav object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageSwitch) name:Notification_Switch_Language object:nil];
}
- (void)languageSwitch {
for (UIView *obj in self.subviews) {
[obj removeFromSuperview];
}
[self createSubViews];
}
- (void)createSubViews
{
UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, PUB_NAVBAR_HEIGHT, self.width, 10)];
bottomLine.userInteractionEnabled = YES;
bottomLine.image = [UIImage imageNamed:@"navbar_bottom_line"];
[self addSubview:bottomLine];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0f, PUB_NAVBAR_HEIGHT - 64.0f, 64.0f, 64.0f);
button.backgroundColor = [UIColor clearColor];
button.adjustsImageWhenHighlighted = NO;
[button.titleLabel setFont:kMainFont];
[button setTitleColor:kBlackColor forState:UIControlStateNormal];
[button setImage:[[UIImage imageNamed:@"public_back"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(30, 14, 10, 26)];
[button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[button setTintColor:kBlackColor];
[button addTarget:self action:@selector(popViewController) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
UIView *menuView = [[UIView alloc] init];
menuView.backgroundColor = [UIColor clearColor];
[self addSubview:menuView];
moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
moreButton.backgroundColor = [UIColor clearColor];
moreButton.tintColor = kBlackColor;
[moreButton.titleLabel setFont:kMainFont];
[moreButton setImage:[[UIImage imageNamed:@"book_more"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[moreButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[moreButton addTarget:self action:@selector(moreEvent) forControlEvents:UIControlEventTouchUpInside];
moreButton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10);
[menuView addSubview:moreButton];
moreButton.hidden = NO;
#if TF_Download_Mode
UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
downloadButton.hidden = NO;
downloadButton.adjustsImageWhenHighlighted = NO;
downloadButton.tintColor = kBlackColor;
[downloadButton setImage:[[UIImage imageNamed:@"public_download"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[downloadButton setImageEdgeInsets:UIEdgeInsetsMake(11, 11, 11, 11)];
[downloadButton addTarget:self action:@selector(downloadButtonClick) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:downloadButton];
downloadButton.hidden = NO;
#endif
//#if TF_Enable_Ai
UIButton *radioButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.radioButton = radioButton;
radioButton.hidden = NO;
radioButton.adjustsImageWhenHighlighted = NO;
radioButton.tintColor = kBlackColor;
[radioButton setImage:[[UIImage imageNamed:@"audio_book"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[radioButton setImageEdgeInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
[radioButton addTarget:self action:@selector(radioButtonClick) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:radioButton];
radioButton.hidden = NO;
//#endif
#if TF_Enable_Gift
UIButton *giftButton = [UIButton buttonWithType:UIButtonTypeCustom];
giftButton.hidden = NO;
giftButton.adjustsImageWhenHighlighted = NO;
giftButton.tintColor = kBlackColor;
[giftButton setImage:[[UIImage imageNamed:@"book_gift"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[giftButton setImageEdgeInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
[giftButton addTarget:self action:@selector(giftButtonClick) forControlEvents:UIControlEventTouchUpInside];
[menuView addSubview:giftButton];
#endif
NSMutableArray *buttonMenuArr = [NSMutableArray arrayWithObjects:
#if TF_Download_Mode
downloadButton,
#endif
moreButton,
nil];
self.buttonMenuArr = buttonMenuArr;
#if TF_Enable_Ai
if ([TFUtilsHelper getAiReadSwitchState]) {
[buttonMenuArr insertObject:radioButton atIndex:0];
} else {
radioButton.hidden = YES;
}
#endif
#if TF_Enable_Gift
AppDelegate *app = (AppDelegate *)kRCodeSync([UIApplication sharedApplication].delegate);
TFCheckSettingModel *model = app.checkSettingModel;
if (TF_Enable_Gift && (model.system_setting.novel_reward_switch == 1 || model.system_setting.monthly_ticket_switch == 1)) {
[buttonMenuArr insertObject:giftButton atIndex:0];
giftButton.hidden = NO;
} else {
giftButton.hidden = YES;
}
#endif
[menuView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.mas_right).with.offset(- kHalfMargin);
make.bottom.mas_equalTo(self.mas_bottom);
make.width.mas_equalTo(40 * buttonMenuArr.count + (buttonMenuArr.count - 1) * kHalfMargin);
make.height.mas_equalTo(40);
}];
[buttonMenuArr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:10 leadSpacing:0 tailSpacing:0];
[buttonMenuArr mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
make.height.mas_equalTo(40);
make.width.mas_equalTo(40);
}];
}
// 隐藏导航条
- (void)hiddenNavBarCompletion:(void(^)(void))completion
{
if (!_navBarShowing && functionalManager.state != TFReaderAutoReadStatePause && functionalManager.state != TFReaderAutoReadStateStop) {
return;
}
[functionalManager hiddenStatusBar];
[UIView animateWithDuration:kAnimatedDurationFast animations:^{
self.frame = CGRectMake(0, - PUB_NAVBAR_HEIGHT, SCREEN_WIDTH, PUB_NAVBAR_HEIGHT);
} completion:^(BOOL finished) {
if (completion) {
self.navBarShowing = NO;
!completion ?: completion();
}
}];
}
- (void)hiddenNavBar
{
[self hiddenNavBarCompletion:nil];
}
// 显示导航条
- (void)showNavBarCompletion:(void(^)(void))completion
{
if (_navBarShowing) {
return;
}
[functionalManager showStatusBar];
[TFViewHelper setStateBarDefaultStyle];
[UIView animateWithDuration:kAnimatedDurationFast animations:^{
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, PUB_NAVBAR_HEIGHT);
} completion:^(BOOL finished) {
if (completion) {
self.navBarShowing = YES;
!completion ?: completion();
}
}];
}
#if TF_Download_Mode
- (void)downloadButtonClick
{
TFNovelDownloadMenuView *downloadBar = [[TFNovelDownloadMenuView alloc] init];
downloadBar.book_id = [TFUtilsHelper formatStringWithInteger:[TFReaderBookManager sharedManager].book_id];
downloadBar.chapter_id = [TFUtilsHelper formatStringWithInteger:[TFReaderBookManager sharedManager].chapter_id];
[kMainWindow addSubview:downloadBar];
[downloadBar showDownloadPayView];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_Bottom_ToolNav object:nil];
}
#endif
#if TF_Enable_Ai
- (void)radioButtonClick
{
if ([TFNetworkManager networkingStatus] == NO) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"听书功能仅支持在线使用")];
return;
}
TFProductionModel *bookModel = [TFReaderBookManager sharedManager].bookModel;
TFProductionChapterModel *bookChapterModel = [[TFProductionChapterModel alloc] init];
for (TFProductionChapterModel *t_model in bookModel.chapter_list) {
if (t_model.chapter_id == [TFReaderBookManager sharedManager].chapter_id) {
bookChapterModel = t_model;
break;
}
}
WXYZ_BookAiPlayPageViewController *vc = [WXYZ_BookAiPlayPageViewController sharedManager];
[vc loadDataWithBookModel:bookModel chapterModel:bookChapterModel];
if ([[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAi]) {
[vc popViewController];
} else if (![[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAi] && [[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio]) {
[[TFAudioPlayViewController sharedManager] popViewController];
UINavigationController *nav = [TFViewHelper getCurrentNavigationController];
if ([nav.viewControllers.lastObject isKindOfClass:TFAudioDetailViewController.class]) {
TFNavigationController *t_nav = [[TFNavigationController alloc] initWithRootViewController:vc];
[[TFViewHelper getCurrentViewController] presentViewController:t_nav animated:YES completion:nil];
} else {
[[TFAudioPlayViewController sharedManager] popViewController];
}
} else if ([[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAi] && [[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio]) {
[[TFAudioPlayViewController sharedManager] popViewController];
[[TFAudioPlayViewController sharedManager] popViewController];
} else {
TFNavigationController *nav = [[TFNavigationController alloc] initWithRootViewController:vc];
nav.view.tag = 2345;
[[TFViewHelper getWindowRootController] presentViewController:nav animated:YES completion:nil];
}
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_Bottom_ToolNav object:nil];
}
#endif
- (void)giftButtonClick {
WXYZ_GiftView *mainView = [[WXYZ_GiftView alloc] initWithFrame:CGRectZero bookModel:[TFReaderBookManager sharedManager].bookModel];
[mainView show];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_Bottom_ToolNav object:nil];
}
// 返回
- (void)popViewController
{
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Back object:nil];
}
- (void)moreEvent {
WXYZ_MoreView *mainView = [[WXYZ_MoreView alloc] init];
[mainView show];
}
@end
@@ -0,0 +1,22 @@
//
// WXYZ_MoreView.h
// WXReader
//
// Created by LL on 2020/5/22.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 阅读器更多功能视图
@interface WXYZ_MoreView : UIView
- (void)hide;
- (void)show;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,392 @@
//
// WXYZ_MoreView.m
// WXReader
//
// Created by LL on 2020/5/22.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_MoreView.h"
#import "UIView+LayoutCallback.h"
#import "NSObject+Observer.h"
#import "TFReaderBookManager.h"
#import "TFCollectionManager.h"
#import "TFNovelDetailViewController.h"
#import "TFShareManager.h"
#import "TFReadRecordManager.h"
#import "TFBookMarkModel.h"
#import "WXYZ_BookReaderMenuBar.h"
@interface WXYZ_MoreCell : UICollectionViewCell
- (void)setDict:(NSDictionary <NSString *, NSString *> *)dict;
@end
typedef NS_ENUM(NSInteger, ReaderBookStyle) {
ReaderBookDetail = 0,
ReaderBookMark,
ReaderBookRack,
ReaderBookShare,
};
@interface WXYZ_MoreView ()<UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSArray<NSDictionary *> *moreDict;
@property (nonatomic, weak) UIView *mainView;
/// 背景视图
@property (nonatomic, weak) UIView *emptyView;
@property (nonatomic, strong) TFProductionModel *bookModel;
@property (nonatomic, strong) TFReaderBookManager *bookManager;
/// 书签状态
@property (nonatomic, assign) BOOL markStatus;
/// 书签Model
@property (nonatomic, strong) TFBookMarkModel *markModel;
/// 是不是封面
@property (nonatomic, assign) BOOL isCover;
@end
@implementation WXYZ_MoreView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
[self createSubviews];
}
return self;
}
- (void)initialize {
self.bookModel = [TFReaderBookManager sharedManager].bookModel;
self.bookManager = [TFReaderBookManager sharedManager];
// 章节内容
NSString *chapterContent = [self.bookManager getChapterContent];
// 页面内容
NSString *pageContent = [self.bookManager getChapterDetailContent];
NSRange range = [chapterContent rangeOfString:pageContent];
if (self.isCover) {// 封面不能添加书签
self.markStatus = NO;
} else {
// 获取当前章节所有的书签
NSArray<TFBookMarkModel *> *markArr = [TFReadRecordManager bookMark:[TFUtilsHelper formatStringWithInteger:self.bookManager.book_id] chapterID:[TFUtilsHelper formatStringWithInteger:self.bookManager.chapter_id]];
for (TFBookMarkModel *t_model in markArr) {
if (t_model.specificIndex >= range.location && t_model.specificIndex < (range.location + range.length)) {
self.markModel = t_model;
self.markStatus = YES;
break;
}
}
}
}
- (void)createSubviews {
self.backgroundColor = kBlackTransparentColor;
[kMainWindow addSubview:self];
[self mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(kMainWindow);
}];
UIView *emptyView = [[UIView alloc] init];
self.emptyView = emptyView;
emptyView.backgroundColor = [UIColor clearColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
[emptyView addGestureRecognizer:tap];
[self addSubview:emptyView];
[emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
UIView *mainView = [[UIView alloc] init];
self.mainView = mainView;
mainView.backgroundColor = [UIColor whiteColor];
mainView.frameBlock = ^(UIView * _Nonnull view) {
UIBezierPath *corner = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(12.0, 12.0)];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = corner.CGPath;
view.layer.mask = layer;
};
[self addSubview:mainView];
[mainView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_bottom);
make.left.right.equalTo(self);
make.height.mas_equalTo(100 + 25 + 25 + PUB_TABBAR_HEIGHT);
}];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.estimatedItemSize = CGSizeMake(62.0, 60.0f);
CGFloat spacing = (SCREEN_WIDTH - (2 * kMargin) - (self.moreDict.count * flowLayout.estimatedItemSize.width)) / (self.moreDict.count - 1);
spacing = spacing < kMargin ? kMargin : spacing;
flowLayout.minimumInteritemSpacing = spacing;
flowLayout.minimumLineSpacing = kMargin;
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerClass:[WXYZ_MoreCell class] forCellWithReuseIdentifier:@"Identifier"];
collectionView.backgroundColor = [UIColor clearColor];
collectionView.showsVerticalScrollIndicator = NO;
collectionView.showsHorizontalScrollIndicator = NO;
[mainView addSubview:collectionView];
[collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(mainView).offset(25);
make.left.equalTo(mainView).offset(kMargin);
make.right.equalTo(mainView).offset(- kMargin);
make.height.mas_equalTo(100);
}];
[collectionView addObserver:KEY_PATH(collectionView, contentSize) complete:^(UICollectionView * _Nonnull obj, id _Nullable oldVal, id _Nullable newVal) {
CGSize size = [newVal CGSizeValue];
[obj mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(size.height);
}];
}];
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
[closeButton setTitle:TFLocalizedString(@"关闭") forState:UIControlStateNormal];
[closeButton setTitleColor:kBlackColor forState:UIControlStateNormal];
[closeButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, PUB_TABBAR_OFFSET / 2, 0)];
closeButton.titleLabel.font = kFont16;
[mainView addSubview:closeButton];
[closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(PUB_TABBAR_HEIGHT);
make.left.width.equalTo(mainView);
make.top.equalTo(collectionView.mas_bottom).offset(25.0f);
}];
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
[closeButton addGestureRecognizer:tap];
UIView *splitLine = [[UIView alloc] init];
splitLine.backgroundColor = kGrayLineColor;
[mainView addSubview:splitLine];
[splitLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(0.5);
make.left.width.top.equalTo(closeButton);
}];
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (void)show {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_bottom).offset(- CGRectGetHeight(self.mainView.frame));
}];
[self.mainView.superview layoutIfNeeded];
}];
}
- (void)hide {
[UIView animateWithDuration:kAnimatedDuration animations:^{
[self.mainView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_bottom);
}];
[self.mainView.superview layoutIfNeeded];
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
[[WXYZ_BookReaderMenuBar sharedManager] hiddend];
}
}];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint emptyPoint = [self convertPoint:point toView:self.mainView];
if ([self.mainView pointInside:emptyPoint withEvent:event]) {
return [super hitTest:point withEvent:event];
} else {
return self.emptyView;
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.moreDict.count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
WXYZ_MoreCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Identifier" forIndexPath:indexPath];
[cell setDict:self.moreDict[indexPath.row].allValues.firstObject];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dict = self.moreDict[indexPath.row];
ReaderBookStyle style = [dict.allKeys.firstObject integerValue];
switch (style) {
case ReaderBookDetail:
{
[self hide];
UINavigationController *nav = [TFViewHelper getCurrentNavigationController];
if (nav.viewControllers.count > 1) {
UIViewController *tmp = nav.viewControllers[nav.viewControllers.count - 2];
if ([tmp isKindOfClass:TFNovelDetailViewController.class]) {
[nav popViewControllerAnimated:YES];
return;
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Reader_Push object:@"TFNovelDetailViewController"];
}
break;
case ReaderBookMark:
{
if (self.isCover) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"当前页不支持加书签")];
return;
}
NSString *pageContent = [self.bookManager getChapterDetailContent];
if ([pageContent isEqualToString:@"\uFFFC"]) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"当前页不支持加书签")];
return;
}
NSDictionary *dict = nil;
if (self.markStatus) {
// 移除书签
[TFReadRecordManager removeBookMark:self.markModel];
dict = @{@(ReaderBookMark) : @{TFLocalizedString(@"添加书签") : @"book_add_mark"}};
self.markStatus = NO;
} else {
// 添加书签
self.markModel = [TFReadRecordManager addBookMark:[TFUtilsHelper formatStringWithInteger:self.bookManager.book_id] chapterID:[TFUtilsHelper formatStringWithInteger:self.bookManager.chapter_id] chapterSort:self.bookManager.currentChapterIndex chapterTitle:[self.bookManager getChapterTitle] chapterContent:[self.bookManager getChapterContent] pageContent:pageContent];
dict = @{@(ReaderBookMark) : @{TFLocalizedString(@"取消书签") : @"book_remove_mark"}};
self.markStatus = YES;
}
NSMutableArray<NSDictionary *> *arr = [NSMutableArray arrayWithArray:self.moreDict];
[arr replaceObjectAtIndex:indexPath.row withObject:dict];
self.moreDict = [arr copy];
[collectionView reloadData];
}
break;
case ReaderBookRack:
{
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) break;
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] addCollectionWithProductionModel:self.bookModel atIndex:0]) {
[TFUtilsHelper synchronizationRackProductionWithProduction_id:self.bookModel.production_id productionType:TFProductionTypeNovel complete:nil];
NSDictionary *dict = @{@(ReaderBookRack) : @{TFLocalizedString(@"已加入书架") : @"book_remove_rack"}};
NSMutableArray<NSDictionary *> *arr = [NSMutableArray arrayWithArray:self.moreDict];
[arr replaceObjectAtIndex:indexPath.row withObject:dict];
self.moreDict = [arr copy];
[collectionView reloadData];
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"添加失败")];
}
}
break;
case ReaderBookShare:
{
[self hide];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_ToolNav object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Hidden_Bottom_ToolNav object:nil];
[TFShareManager shareWithProduction_id:NSStringFromInteger(self.bookModel.production_id) chapter_id:NSStringFromInteger(self.bookManager.chapter_id) type:TFShareTypeBook];
}
break;
default:
break;
};
}
- (NSArray<NSDictionary *> *)moreDict {
if (!_moreDict) {
NSMutableArray<NSDictionary *> *arr = [NSMutableArray array];
[arr addObject:@{@(ReaderBookDetail) : @{TFLocalizedString(@"书籍详情") : @"book_detail"}}];
if (self.markStatus) {
[arr addObject:@{@(ReaderBookMark) : @{TFLocalizedString(@"取消书签") : @"book_remove_mark"}}];
} else {
[arr addObject:@{@(ReaderBookMark) : @{TFLocalizedString(@"添加书签") : @"book_add_mark"}}];
}
if ([[TFCollectionManager shareManagerWithProductionType:TFProductionTypeNovel] isCollectedWithProductionModel:self.bookModel]) {
[arr addObject:@{@(ReaderBookRack) : @{TFLocalizedString(@"已加入书架") : @"book_remove_rack"}}];
} else {
[arr addObject:@{@(ReaderBookRack) : @{TFLocalizedString(@"加入书架") : @"book_add_rack"}}];
}
[arr addObject:@{@(ReaderBookShare) : @{TFLocalizedString(@"分享") : @"book_share"}}];
_moreDict = [arr copy];
}
return _moreDict;
}
- (BOOL)isCover {
return self.bookManager.currentChapterIndex == 0 && self.bookManager.currentPagerIndex == 0;
}
@end
@implementation WXYZ_MoreCell {
UIImageView *_coverImageView;
UILabel *_titleLabel;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self createSubviews];
}
return self;
}
- (void)createSubviews {
_coverImageView = [[UIImageView alloc] init];
_coverImageView.contentMode = UIViewContentModeScaleAspectFill;
_coverImageView.clipsToBounds = YES;
_coverImageView.userInteractionEnabled = NO;
_coverImageView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:_coverImageView];
[_coverImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.width.equalTo(self.contentView);
make.height.equalTo(_coverImageView.mas_width);
}];
_titleLabel = [[UILabel alloc] init];
_titleLabel.textColor = kBlackColor;
_titleLabel.font = kFont13;
_titleLabel.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:_titleLabel];
[_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_coverImageView.mas_bottom).offset(14.0f);
make.centerX.equalTo(self.contentView);
make.bottom.equalTo(self.contentView).priorityLow();
}];
}
- (void)setDict:(NSDictionary <NSString *, NSString *> *)dict {
_coverImageView.image = [UIImage imageNamed:dict.allValues.firstObject];
_titleLabel.text = dict.allKeys.firstObject ?: @"";
}
- (UICollectionViewLayoutAttributes*)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes*)layoutAttributes {
[self setNeedsLayout];
[self layoutIfNeeded];
CGSize size = [self.contentView systemLayoutSizeFittingSize:layoutAttributes.size];
CGRect cellFrame = layoutAttributes.frame;
cellFrame.size.height = size.height;
layoutAttributes.frame = cellFrame;
return layoutAttributes;
}
@end
@@ -0,0 +1,17 @@
//
// WXYZ_FeedbackAddCollectionViewCell.h
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackAddCollectionViewCell : UICollectionViewCell
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,36 @@
//
// WXYZ_FeedbackAddCollectionViewCell.m
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackAddCollectionViewCell.h"
@implementation WXYZ_FeedbackAddCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self createSubviews];
}
return self;
}
- (void)createSubviews
{
self.backgroundColor = kGrayViewColor;
UIImageView *addImage = [[UIImageView alloc] init];
addImage.image = [UIImage imageNamed:@"public_rack_add"];
[self addSubview:addImage];
[addImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.mas_centerX);
make.centerY.mas_equalTo(self.mas_centerY);
make.width.height.mas_equalTo(self.mas_width).multipliedBy(0.3);
}];
}
@end
@@ -0,0 +1,30 @@
//
// WXYZ_FeedbackCollectionViewCell.h
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WXYZ_FeedbackPhotoModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackCollectionViewCell : UICollectionViewCell
@property (nonatomic, strong) WXYZ_FeedbackPhotoModel *photoModel;
@property (nonatomic, strong) UIImage *uploadImage;
@property (nonatomic, strong) UIImageView *feedbackImage;
@property (nonatomic, assign) NSInteger cellIndex;
@property (nonatomic, copy) void(^deleteImageBlock)(NSInteger index);
@property (nonatomic, copy) void(^finishedUploadBlock)(NSString *img);
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,94 @@
//
// WXYZ_FeedbackCollectionViewCell.m
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackCollectionViewCell.h"
#import "WXYZ_FeedbackPhotoManager.h"
@interface WXYZ_FeedbackCollectionViewCell ()
@property (nonatomic, strong) UIActivityIndicatorView *activityView;
@property (nonatomic, strong) UIButton *closeButton;
@end
@implementation WXYZ_FeedbackCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self createSubviews];
}
return self;
}
- (void)createSubviews
{
self.feedbackImage = [[UIImageView alloc] init];
self.feedbackImage.contentMode = UIViewContentModeScaleAspectFill;
self.feedbackImage.clipsToBounds = YES;
self.feedbackImage.image = HoldImage;
[self addSubview:self.feedbackImage];
[self.feedbackImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
self.activityView = [[UIActivityIndicatorView alloc] init];
self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
self.activityView.hidesWhenStopped = YES;
[self addSubview:self.activityView];
[self.activityView startAnimating];
[self.activityView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.mas_centerX);
make.centerY.mas_equalTo(self.mas_centerY);
make.width.height.mas_equalTo(30);
}];
self.closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.closeButton.hidden = YES;
self.closeButton.adjustsImageWhenHighlighted = NO;
[self.closeButton setImageEdgeInsets:UIEdgeInsetsMake(0, 10, 10, 0)];
[self.closeButton setImage:[UIImage imageNamed:@"feedback_photo_delete"] forState:UIControlStateNormal];
[self.closeButton addTarget:self action:@selector(deleteClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.closeButton];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.mas_right);
make.top.mas_equalTo(self.mas_top);
make.width.height.mas_equalTo(self.mas_width).multipliedBy(0.3);
}];
}
- (void)setPhotoModel:(WXYZ_FeedbackPhotoModel *)photoModel
{
_photoModel = photoModel;
if (photoModel.show_img.length > 0) {
WS(weakSelf)
[self.feedbackImage setImageWithURL:[NSURL URLWithString:photoModel.show_img] placeholder:HoldImage options:YYWebImageOptionSetImageWithFadeAnimation completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
[weakSelf.activityView stopAnimating];
weakSelf.closeButton.hidden = NO;
}];
} else {
self.feedbackImage.image = HoldImage;
[self.activityView startAnimating];
self.closeButton.hidden = YES;
}
}
- (void)deleteClick
{
[[WXYZ_FeedbackPhotoManager sharedManager] deletePhotoWithPhotoModel:self.photoModel];
}
@end
@@ -0,0 +1,19 @@
//
// WXYZ_FeedbackContactTableViewCell.h
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackContactTableViewCell : TFBasicTableViewCell
@property (nonatomic, copy) void(^contactDidChange)(NSString *contactString);
@property (nonatomic, copy) void(^willBeginEditing)(void);
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,71 @@
//
// WXYZ_FeedbackContactTableViewCell.m
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackContactTableViewCell.h"
@interface WXYZ_FeedbackContactTableViewCell () <UITextFieldDelegate>
{
UITextField *textField;
}
@property (nonatomic, copy) NSString *contactString;
@end
@implementation WXYZ_FeedbackContactTableViewCell
- (void)createSubviews
{
[super createSubviews];
textField = [[UITextField alloc] init];
textField.backgroundColor = [UIColor clearColor];
textField.font = kMainFont;
textField.delegate = self;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.textColor = kBlackColor;
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:TFLocalizedString(@"邮箱/手机号")];
[attributedString setAttributes:@{NSFontAttributeName:kMainFont, NSForegroundColorAttributeName:kColorRGBA(199, 199, 205, 1)} range:NSMakeRange(0, attributedString.length)];
textField.attributedPlaceholder = attributedString;
[self.contentView addSubview:textField];
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kMargin);
make.top.mas_equalTo(self.contentView.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH - 2 * kMargin);
make.height.mas_equalTo(KCellHeight);
make.bottom.mas_equalTo(self.contentView.mas_bottom).priorityLow();
}];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string isEqualToString:@""]) {
return YES;
}
if (textField.text.length >= 30) {
textField.text = [textField.text substringToIndex:30];
return NO;
}
if (self.contactDidChange) {
self.contactDidChange(textField.text);
}
return YES;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (self.willBeginEditing) {
self.willBeginEditing();
}
return YES;
}
@end
@@ -0,0 +1,30 @@
//
// WXYZ_FeedbackPhotoManager.h
// WXReader
//
// Created by Andrew on 2019/12/28.
// Copyright © 2019 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WXYZ_FeedbackPhotoModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackPhotoManager : NSObject
@property (nonatomic, assign, readonly) BOOL isUploading;
@property (nonatomic, copy) void(^deletePhotoBlock)(WXYZ_FeedbackPhotoModel *photoModel);
interface_singleton
- (void)addPhotoImage:(UIImage *)image complete:(void(^)(WXYZ_FeedbackPhotoModel *photoModel))completeBlock;
- (void)deletePhotoWithPhotoModel:(WXYZ_FeedbackPhotoModel *)photoModel;
- (void)removeAllPhotoImageWithPhotoArray:(NSArray *)dataSources;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,97 @@
//
// WXYZ_FeedbackPhotoManager.m
// WXReader
//
// Created by Andrew on 2019/12/28.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackPhotoManager.h"
@interface WXYZ_FeedbackPhotoManager ()
@property (nonatomic, strong) NSMutableSet *uploadSet;
@end
@implementation WXYZ_FeedbackPhotoManager
implementation_singleton(WXYZ_FeedbackPhotoManager)
- (instancetype)init
{
if (self = [super init]) {
self.uploadSet = [NSMutableSet set];
}
return self;
}
- (void)addPhotoImage:(UIImage *)image complete:(void(^)(WXYZ_FeedbackPhotoModel *photoModel))completeBlock
{
NSString *imageBase64 = [TFViewHelper getBase64StringWithImageData:UIImagePNGRepresentation(image)];
if (imageBase64.length == 0 || !imageBase64) {
if (completeBlock) {
completeBlock(nil);
}
return;
}
[self.uploadSet addObject:@"upload"];
WS(weakSelf)
[TFNetworkTools POST:Upload_Image parameters:@{@"image":imageBase64} model:WXYZ_FeedbackPhotoModel.class success:^(BOOL isSuccess, id _Nullable t_model, TFNetworkRequestModel *requestModel) {
if (isSuccess) {
!completeBlock ?: completeBlock(t_model);
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"图片上传失败")];
!completeBlock ?: completeBlock(nil);
}
[weakSelf.uploadSet removeObject:[weakSelf.uploadSet anyObject]];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[TFPromptManager showPromptWithError:error defaultText:nil];
// [weakSelf.uploadSet removeObject:[weakSelf.uploadSet anyObject]];
!completeBlock ?: completeBlock(nil);
}];
}
- (BOOL)isUploading
{
return self.uploadSet.count > 0;
}
- (void)deletePhotoWithPhotoModel:(WXYZ_FeedbackPhotoModel *)photoModel
{
if (photoModel.show_img.length <= 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"图片删除失败")];
return;
}
[self removeAllPhotoImageWithPhotoArray:@[photoModel]];
if (photoModel) {
if (self.deletePhotoBlock) {
self.deletePhotoBlock(photoModel);
}
}
}
- (void)removeAllPhotoImageWithPhotoArray:(NSArray *)dataSources
{
[self.uploadSet removeAllObjects];
if (dataSources.count <= 0) {
return;
}
NSMutableArray *imgs = [NSMutableArray arrayWithCapacity:3];
for (WXYZ_FeedbackPhotoModel *t_model in dataSources) {
if (t_model.img) {
[imgs addObject:t_model.img];
}
}
[TFNetworkTools POST:Delete_Upload_Image parameters:@{@"image":[imgs componentsJoinedByString:@"||"]} model:nil success:nil failure:nil];
}
@end
@@ -0,0 +1,21 @@
//
// WXYZ_FeedbackPhotoModel.h
// WXReader
//
// Created by Andrew on 2019/12/28.
// Copyright © 2019 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackPhotoModel : NSObject
@property (nonatomic, copy) NSString *img; // 图片相对地址,这个值传递保存
@property (nonatomic, copy) NSString *show_img; // 图片显示地址
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,13 @@
//
// WXYZ_FeedbackPhotoModel.m
// WXReader
//
// Created by Andrew on 2019/12/28.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackPhotoModel.h"
@implementation WXYZ_FeedbackPhotoModel
@end
@@ -0,0 +1,18 @@
//
// WXYZ_FeedbackPhotoTableViewCell.h
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_ImagePicker.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackPhotoTableViewCell : TFBasicTableViewCell <DPImagePickerDelegate, UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonatomic, copy) void(^operationPhotosBlock)(NSMutableArray *photosSource);
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,144 @@
//
// WXYZ_FeedbackPhotoTableViewCell.m
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackPhotoTableViewCell.h"
#import "WXYZ_FeedbackAddCollectionViewCell.h"
#import "WXYZ_FeedbackCollectionViewCell.h"
#import "TFPhotoBrowser.h"
#import "WXYZ_FeedbackPhotoManager.h"
#import "NSObject+Observer.h"
@interface WXYZ_FeedbackPhotoTableViewCell ()
@property (nonatomic, strong) NSMutableArray *photosSource;
@property (nonatomic, strong) UICollectionView *mainCollectionView;
@end
@implementation WXYZ_FeedbackPhotoTableViewCell
- (void)createSubviews
{
[super createSubviews];
self.photosSource = [NSMutableArray array];
UICollectionViewFlowLayout *mainCollectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
mainCollectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
mainCollectionViewFlowLayout.minimumLineSpacing = kHalfMargin;
mainCollectionViewFlowLayout.minimumInteritemSpacing = 0;
CGFloat width = (SCREEN_WIDTH - (2 * kHalfMargin) - (2 * mainCollectionViewFlowLayout.minimumLineSpacing)) / 3.0;
mainCollectionViewFlowLayout.itemSize = CGSizeMake(width, width);
self.mainCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:mainCollectionViewFlowLayout];
self.mainCollectionView.userInteractionEnabled = YES;
self.mainCollectionView.backgroundColor = [UIColor clearColor];
self.mainCollectionView.showsVerticalScrollIndicator = NO;
self.mainCollectionView.showsHorizontalScrollIndicator = NO;
self.mainCollectionView.alwaysBounceVertical = YES;
self.mainCollectionView.delegate = self;
self.mainCollectionView.dataSource = self;
if (@available(iOS 11.0, *)) {
self.mainCollectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
// Fallback on earlier versions
}
[self.mainCollectionView registerClass:[WXYZ_FeedbackCollectionViewCell class] forCellWithReuseIdentifier:@"WXYZ_FeedbackCollectionViewCell"];
[self.mainCollectionView registerClass:[WXYZ_FeedbackAddCollectionViewCell class] forCellWithReuseIdentifier:@"WXYZ_FeedbackAddCollectionViewCell"];
[self.contentView addSubview:self.mainCollectionView];
[self.mainCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(self.contentView.mas_top).with.offset(kHalfMargin);
make.height.mas_equalTo(width);
make.width.mas_equalTo(SCREEN_WIDTH - kMargin);
make.bottom.mas_equalTo(self.contentView.mas_bottom).with.offset(- kHalfMargin).priorityLow();
}];
WS(weakSelf)
[WXYZ_FeedbackPhotoManager sharedManager].deletePhotoBlock = ^(WXYZ_FeedbackPhotoModel * _Nonnull photoModel) {
[weakSelf.photosSource removeObject:photoModel];
[weakSelf.mainCollectionView reloadData];
if (weakSelf.operationPhotosBlock) {
weakSelf.operationPhotosBlock(weakSelf.photosSource);
}
};
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (self.photosSource.count < 3) {
return self.photosSource.count + 1;
}
if (self.photosSource.count >= 3) {
return 3;
}
return self.photosSource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.photosSource.count && self.photosSource.count < 3) {
static NSString *CellIdentifier = @"WXYZ_FeedbackAddCollectionViewCell";
WXYZ_FeedbackAddCollectionViewCell __weak *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
} else {
WS(weakSelf)
static NSString *CellIdentifier = @"WXYZ_FeedbackCollectionViewCell";
WXYZ_FeedbackCollectionViewCell __weak *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cell.photoModel = [self.photosSource objectOrNilAtIndex:indexPath.row];
cell.cellIndex = indexPath.row;
cell.deleteImageBlock = ^(NSInteger index) {
[weakSelf.mainCollectionView reloadData];
};
return cell;
}
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([[collectionView cellForItemAtIndexPath:indexPath] isKindOfClass:[WXYZ_FeedbackAddCollectionViewCell class]]) {
WXYZ_ImagePicker *picker = [WXYZ_ImagePicker sharedManager];
picker.editPhoto = NO;
picker.delegate = self;
[picker showLibraryInController:[TFViewHelper getCurrentViewController]];
} else {
WXYZ_FeedbackPhotoModel *photoModel = [self.photosSource objectOrNilAtIndex:indexPath.row];
TFPhotoBrowser *browser = [TFPhotoBrowser new];
browser.dataSource = @[photoModel.show_img].mutableCopy;
browser.downLoadNeeded = YES;
browser.currentPhotoIndex = 0;
[[TFViewHelper getCurrentViewController] presentViewController:browser animated:YES completion:nil];
}
}
- (void)imagePickerDidFinishPickingWithOriginalImage:(UIImage *)originalImage editedImage:(UIImage *)editedImage
{
WS(weakSelf)
WXYZ_FeedbackPhotoModel *photoModel = [[WXYZ_FeedbackPhotoModel alloc] init];
photoModel.show_img = @"";
[self.photosSource addObject:photoModel];
[self.mainCollectionView reloadData];
[[WXYZ_FeedbackPhotoManager sharedManager] addPhotoImage:originalImage complete:^(WXYZ_FeedbackPhotoModel * _Nonnull photoModel) {
if (photoModel) {
[weakSelf.photosSource removeLastObject];
[weakSelf.photosSource addObject:photoModel];
[weakSelf.mainCollectionView reloadData];
if (weakSelf.operationPhotosBlock) {
weakSelf.operationPhotosBlock(weakSelf.photosSource);
}
}
}];
}
@end
@@ -0,0 +1,12 @@
//
// WXYZ_FeedbackSubViewController.h
// WXReader
//
// Created by Andrew on 2018/7/4.
// Copyright © 2018年 Andrew. All rights reserved.
//
@interface WXYZ_FeedbackSubViewController : TFBasicViewController
@end
@@ -0,0 +1,301 @@
//
// WXYZ_FeedbackSubViewController.m
// WXReader
//
// Created by Andrew on 2018/7/4.
// Copyright © 2018年 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackSubViewController.h"
#import "WXYZ_FeedbackTextViewTableViewCell.h"
#import "WXYZ_FeedbackPhotoTableViewCell.h"
#import "WXYZ_FeedbackContactTableViewCell.h"
#import "TFTextView.h"
#import "TFKeyboardManager.h"
#import "WXYZ_FeedbackPhotoManager.h"
@interface WXYZ_FeedbackSubViewController () <UITableViewDelegate, UITableViewDataSource>
{
UIButton *submitButton;
TFKeyboardManager *keyboardManager;
}
@property (nonatomic, strong) NSString *contentString;
@property (nonatomic, strong) NSString *contactString;
@end
@implementation WXYZ_FeedbackSubViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self initialize];
[self createSubviews];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setStatusBarDefaultStyle];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self navigationCanSlidingBack:NO];
}
- (void)initialize
{
[self setNavigationBarTitle:TFLocalizedString(@"意见反馈")];
[self hiddenNavigationBarLeftButton];
self.view.backgroundColor = kGrayViewColor;
}
- (void)createSubviews
{
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeCustom];
leftButton.backgroundColor = [UIColor clearColor];
leftButton.frame = CGRectMake(kHalfMargin, PUB_NAVBAR_OFFSET + 20, 44, 44);
leftButton.adjustsImageWhenHighlighted = NO;
[leftButton.titleLabel setFont:kMainFont];
[leftButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[leftButton setImageEdgeInsets:UIEdgeInsetsMake(12, 6, 12, 18)];
[leftButton setImage:[[UIImage imageNamed:@"public_back"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
[leftButton setTintColor:kBlackColor];
[leftButton addTarget:self action:@selector(giveUpSubmit) forControlEvents:UIControlEventTouchUpInside];
[self.navigationBar addSubview:leftButton];
self.mainTableViewGroup.delegate = self;
self.mainTableViewGroup.dataSource = self;
[self.view addSubview:self.mainTableViewGroup];
[self.mainTableViewGroup mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.top.mas_equalTo(PUB_NAVBAR_HEIGHT);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(SCREEN_HEIGHT - PUB_NAVBAR_HEIGHT - PUB_TABBAR_HEIGHT);
}];
submitButton = [UIButton buttonWithType:UIButtonTypeCustom];
submitButton.backgroundColor = kRedColor;
[submitButton setTitle:TFLocalizedString(@"提交") forState:UIControlStateNormal];
[submitButton setTitleColor:kWhiteColor forState:UIControlStateNormal];
[submitButton.titleLabel setFont:kMainFont];
[submitButton addTarget:self action:@selector(netRequest) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:submitButton];
[submitButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.view.mas_bottom).with.offset(- PUB_TABBAR_OFFSET);
make.left.mas_equalTo(0);
make.width.mas_equalTo(SCREEN_WIDTH);
make.height.mas_equalTo(PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET);
}];
WS(weakSelf)
keyboardManager = [[TFKeyboardManager alloc] initObserverWithAdaptiveMovementView:self.mainTableViewGroup];
keyboardManager.keyboardHeightChanged = ^(CGFloat keyboardHeight, CGFloat shouldMoveDistance, CGRect shouldMoveFrame) {
[weakSelf.mainTableViewGroup setMj_y:weakSelf.mainTableViewGroup.mj_y + shouldMoveDistance];
};
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
WS(weakSelf)
switch (indexPath.section) {
case 0:
{
static NSString *cellName = @"WXYZ_FeedbackTextViewTableViewCell";
WXYZ_FeedbackTextViewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_FeedbackTextViewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.textViewDidChange = ^(NSString * _Nonnull contentString) {
weakSelf.contentString = contentString;
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
break;
case 1:
{
static NSString *cellName = @"WXYZ_FeedbackPhotoTableViewCell";
WXYZ_FeedbackPhotoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_FeedbackPhotoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.operationPhotosBlock = ^(NSMutableArray * _Nonnull photosSource) {
weakSelf.dataSourceArray = photosSource;
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
break;
case 2:
{
static NSString *cellName = @"WXYZ_FeedbackContactTableViewCell";
WXYZ_FeedbackContactTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (!cell) {
cell = [[WXYZ_FeedbackContactTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellName];
}
cell.contactDidChange = ^(NSString * _Nonnull contactString) {
weakSelf.contactString = contactString;
};
__weak WXYZ_FeedbackContactTableViewCell *weakCell = cell;
cell.willBeginEditing = ^{
keyboardManager.adaptiveMovementView = weakCell;
};
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
break;
default:
break;
}
return [[UITableViewCell alloc] init];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return KCellHeight;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, KCellHeight)];
view.backgroundColor = kGrayViewColor;
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(kHalfMargin, 0, SCREEN_WIDTH - 2 * kHalfMargin, 40)];
titleLabel.textColor = kGrayTextColor;
titleLabel.font = kFont15;
[view addSubview:titleLabel];
switch (section) {
case 0:
titleLabel.text = TFLocalizedString(@"问题反馈");
break;
case 1:
titleLabel.text = TFLocalizedString(@"提供问题截图(选填)");
break;
case 2:
titleLabel.text = TFLocalizedString(@"联系方式(至少填写一项)");
break;
default:
break;
}
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if (section == 2) {
return PUB_TABBAR_OFFSET == 0 ? 10 : PUB_TABBAR_OFFSET;
}
return CGFLOAT_MIN;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, PUB_TABBAR_OFFSET == 0 ? 10 : PUB_TABBAR_OFFSET)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[TFKeyboardManager hideKeyboard];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[TFKeyboardManager hideKeyboard];
}
- (void)giveUpSubmit
{
WS(weakSelf)
if (self.contentString.length > 0 || self.contactString.length > 0 || [WXYZ_FeedbackPhotoManager sharedManager].isUploading || self.dataSourceArray.count > 0) {
TFAlertView *alert = [[TFAlertView alloc] init];
alert.alertDetailContent = TFLocalizedString(@"您有修改尚未提交,是否放弃修改?");
alert.confirmTitle = TFLocalizedString(@"放弃修改");
alert.cancelTitle = TFLocalizedString(@"取消");
alert.confirmButtonClickBlock = ^{
[[WXYZ_FeedbackPhotoManager sharedManager] removeAllPhotoImageWithPhotoArray:weakSelf.dataSourceArray];
[weakSelf popViewController];
};
[alert showAlertView];
return;
}
[self popViewController];
}
- (void)netRequest
{
[TFKeyboardManager hideKeyboard];
if (self.contentString.length == 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"请完善问题描述")];
return;
}
if (self.contactString.length == 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"请填写联系方式")];
return;
}
if ([WXYZ_FeedbackPhotoManager sharedManager].isUploading) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"图片正在上传中,请稍后")];
return;
}
NSMutableDictionary *t_dic = [NSMutableDictionary dictionary];
[t_dic setObject:self.contentString forKey:@"content"];
[t_dic setObject:self.contactString forKey:@"contact"];
if (self.dataSourceArray.count > 0) {
NSMutableArray *imgs = [NSMutableArray arrayWithCapacity:3];
for (WXYZ_FeedbackPhotoModel *t_model in self.dataSourceArray) {
[imgs addObject:t_model.img];
}
[t_dic setObject:[imgs componentsJoinedByString:@"||"] forKey:@"imgs"];
}
submitButton.enabled = NO;
WS(weakSelf)
[TFNetworkTools POST:Sub_Feed_Back parameters:t_dic model:nil success:^(BOOL isSuccess, id _Nullable t_model, TFNetworkRequestModel *requestModel) {
if (isSuccess) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"反馈成功")];
[weakSelf.navigationController popViewControllerAnimated:YES];
} else {
SS(strongSelf)
strongSelf->submitButton.enabled = YES;
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
}
} failure:nil];
}
- (void)dealloc
{
[keyboardManager stopKeyboardObserver];
}
@end
@@ -0,0 +1,17 @@
//
// WXYZ_FeedbackTextViewTableViewCell.h
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_FeedbackTextViewTableViewCell : TFBasicTableViewCell
@property (nonatomic, copy) void(^textViewDidChange)(NSString *contentString);
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,50 @@
//
// WXYZ_FeedbackTextViewTableViewCell.m
// WXReader
//
// Created by Andrew on 2019/12/27.
// Copyright © 2019 Andrew. All rights reserved.
//
#import "WXYZ_FeedbackTextViewTableViewCell.h"
#import "TFTextView.h"
@interface WXYZ_FeedbackTextViewTableViewCell () <TFTextViewDelegate>
@property (nonatomic ,copy) NSString *contentString;
@end
@implementation WXYZ_FeedbackTextViewTableViewCell
{
TFTextView *textView;
}
- (void)createSubviews
{
[super createSubviews];
textView = [[TFTextView alloc] initWithFrame:CGRectZero];
textView.maxWordCount = 200;
textView.delegate = self;
textView.layer.cornerRadius = 4;
[textView resetPlaceholderText:TFLocalizedString(@"请详细描述您遇到的问题并告知具体操作步骤,我们会尽快答复您的问题哦")];
[self.contentView addSubview:textView];
[textView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.contentView.mas_left).with.offset(kHalfMargin);
make.top.mas_equalTo(self.contentView.mas_top);
make.width.mas_equalTo(SCREEN_WIDTH - kMargin);
make.height.mas_equalTo(200);
make.bottom.mas_equalTo(self.contentView.mas_bottom).priorityLow();
}];
}
- (void)textViewDidChange:(NSString *)text
{
if (self.textViewDidChange) {
self.textViewDidChange(text);
}
}
@end
@@ -0,0 +1,70 @@
//
// TFBasicVoiceHeaderView.h
// WXReader
//
// Created by 谢腾飞 on 2020/12/1.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WXYZ_PlayPageModel.h"
#import "CKAudioProgressView.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, TFBasicVoicePlayerState) {
TFBasicVoicePlayerStateLoading,
TFBasicVoicePlayerStatePlaying,
TFBasicVoicePlayerStatePause,
TFBasicVoicePlayerStateStoped,
TFBasicVoicePlayerStateFail
};
@interface TFBasicVoiceHeaderView : UIView
@property (nonatomic ,assign) TFProductionType productionType;
@property (nonatomic ,strong) WXYZ_RelationModel *relationModel;
@property (nonatomic ,strong) NSArray <TFProductionChapterModel *> *chapter_list;
@property (nonatomic ,strong) TFProductionChapterModel *productionChapterModel;
@property (nonatomic ,strong) TFProductionChapterModel *temp_chapterModel; // 临时章节信息记录
@property (nonatomic ,strong) TFButton *timingButton; // 定时按钮
@property (nonatomic ,strong) TFButton *speedButton; // 语速按钮
@property (nonatomic ,strong) TFButton *voiceButton; // 声音按钮
@property (nonatomic ,assign) TFBasicVoicePlayerState playerState;
@property (nonatomic ,strong) CKAudioProgressView *timelineProgress; // 播放进度
@property (nonatomic ,copy) void (^checkOriginalBlock)(TFProductionChapterModel *chapterModel);
@property (nonatomic ,copy) void (^checkRelationProductionBlock)(WXYZ_RelationModel *relationModel);
@property (nonatomic ,copy) void (^resetPlayerBlock)(BOOL immediateReset);
- (instancetype)initWithProductionType:(TFProductionType)productionType;
- (void)createSubviews;
// 上一首
- (void)skipToLastChapter;
// 下一首
- (void)skipToNextChapter;
// 显示充值页
- (void)showPayView;
// 设置关联作品标题
- (void)setRelationViewTitle:(NSString *)title;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,808 @@
//
// TFBasicVoiceHeaderView.m
// WXReader
//
// Created by 谢腾飞 on 2020/12/1.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFBasicVoiceHeaderView.h"
#import "WXYZ_BookAiPlayPageViewController.h"
#import "WXYZ_TouchAssistantView.h"
#import "WXYZ_AudioPlayPageMenuView.h"
#import "WXYZ_ChapterBottomPayBar.h"
#import "TFReadRecordManager.h"
#import "WXYZ_Player.h"
#if __has_include(<iflyMSC/IFlyMSC.h>)
#import "iflyMSC/IFlyMSC.h"
#endif
#import "WXYZ_AudioSettingHelper.h"
#import "TFReaderBookManager.h"
#import "TFReaderSettingHelper.h"
#import "WXYZ_AudioDownloadManager.h"
#import "UIControl+EventInterval.h"
@interface TFBasicVoiceHeaderView ()<CKAudioProgressViewDelegate>
{
TFProductionCoverView *bookImageView; // 作品图片
UILabel *chapterNameLabel;
UILabel *bookNameLabel;
UIButton *fastForwardButton; // 快进
UIButton *fastBackButton; // 快退
UIButton *playButton; // 播放按钮
UIActivityIndicatorView *playButtonIndicator; // 播放loading
UIButton *previousButton; // 上一首
UIButton *nextButton; // 下一首
TFButton *chapterButton; // 目录
TFButton *originalButton; // 原文
UIButton *relationView;
UILabel *relationChapterTitle;
}
@end
@implementation TFBasicVoiceHeaderView
- (instancetype)initWithProductionType:(TFProductionType)productionType
{
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetPlayerInfo) name:Notification_Reset_Player_Inof object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeLanguage) name:Notification_Switch_Language object:nil];
self.productionType = productionType;
[self createSubviews];
}
return self;
}
- (void)changeLanguage
{
self.timingButton.buttonTitle = TFLocalizedString(@"定时");
self.speedButton.buttonTitle = TFLocalizedString(@"语速");
chapterButton.buttonTitle = TFLocalizedString(@"目录");
}
- (void)createSubviews
{
// 作品图片
bookImageView = [[TFProductionCoverView alloc] initWithProductionType:TFProductionTypeNovel coverDirection:TFProductionCoverDirectionVertical];
bookImageView.userInteractionEnabled = YES;
[self addSubview:bookImageView];
[bookImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(self.mas_centerX);
make.top.mas_equalTo(self.mas_top).with.offset(kMargin);
make.width.mas_equalTo(BOOK_WIDTH);
make.height.mas_equalTo(BOOK_HEIGHT);
}];
// 章节名
chapterNameLabel = [[UILabel alloc] init];
chapterNameLabel.textAlignment = NSTextAlignmentCenter;
chapterNameLabel.textColor = kBlackColor;
chapterNameLabel.backgroundColor = kWhiteColor;
chapterNameLabel.font = kBoldFont17;
[self addSubview:chapterNameLabel];
[chapterNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(bookImageView.mas_centerX);
make.top.mas_equalTo(bookImageView.mas_bottom).with.offset(kHalfMargin);
make.width.mas_equalTo(SCREEN_WIDTH - 2 * kMargin);
make.height.mas_equalTo(kLabelHeight);
}];
// 作者
bookNameLabel = [[UILabel alloc] init];
bookNameLabel.backgroundColor = kWhiteColor;
bookNameLabel.textColor = kGrayTextColor;
bookNameLabel.textAlignment = NSTextAlignmentCenter;
bookNameLabel.font = kFont11;
[self addSubview:bookNameLabel];
[bookNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(chapterNameLabel.mas_bottom);
make.centerX.mas_equalTo(chapterNameLabel.mas_centerX);
make.width.mas_equalTo(chapterNameLabel.mas_width);
make.height.mas_equalTo(chapterNameLabel.mas_height);
}];
if (self.productionType == TFProductionTypeAudio) {
fastBackButton = [UIButton buttonWithType:UIButtonTypeCustom];
fastBackButton.tag = 1;
fastBackButton.enabled = NO;
fastBackButton.touchEventInterval = 0.5;
[fastBackButton setImageEdgeInsets:UIEdgeInsetsMake(6, 12, 6, 0)];
[fastBackButton setImage:[UIImage imageNamed:@"audio_fast_back"] forState:UIControlStateNormal];
[fastBackButton addTarget:self action:@selector(adjustProgress:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:fastBackButton];
[fastBackButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.mas_left).with.offset(kMoreHalfMargin);
make.top.mas_equalTo(bookNameLabel.mas_bottom).with.offset(kMargin);
make.width.height.mas_equalTo(30);
}];
fastForwardButton = [UIButton buttonWithType:UIButtonTypeCustom];
fastForwardButton.tag = 0;
fastForwardButton.enabled = NO;
fastForwardButton.touchEventInterval = 0.5;
[fastForwardButton setImageEdgeInsets:UIEdgeInsetsMake(6, 0, 6, 12)];
[fastForwardButton setImage:[UIImage imageNamed:@"audio_fast_forward"] forState:UIControlStateNormal];
[fastForwardButton addTarget:self action:@selector(adjustProgress:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:fastForwardButton];
[fastForwardButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.mas_right).with.offset(- kMoreHalfMargin);
make.centerY.mas_equalTo(fastBackButton.mas_centerY);
make.width.height.mas_equalTo(30);
}];
self.timelineProgress = [[CKAudioProgressView alloc] initWithFrame:CGRectZero type:CKAudioProgressTypeTimeline];
self.timelineProgress.playedBgColor = kMainColor;
self.timelineProgress.cachedBgColor = kMainColorAlpha(0.2);
self.timelineProgress.delegate = self;
self.timelineProgress.userInteractionEnabled = NO;
[self.timelineProgress updateProgress:0 audioLength:0];
[self addSubview:self.timelineProgress];
[self.timelineProgress mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(fastBackButton.mas_right).with.offset(kHalfMargin);
make.right.mas_equalTo(fastForwardButton.mas_left).with.offset(- kHalfMargin);
make.centerY.mas_equalTo(fastBackButton.mas_centerY);
make.height.mas_equalTo(30);
}];
}
playButton = [UIButton buttonWithType:UIButtonTypeCustom];
playButton.adjustsImageWhenHighlighted = NO;
playButton.enabled = NO;
playButton.touchEventInterval = 0.5;
[playButton setImage:[UIImage imageNamed:@"audio_play_loading"] forState:UIControlStateNormal];
[playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:playButton];
[playButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(bookImageView.mas_centerX);
if (self.productionType == TFProductionTypeAudio) {
make.top.mas_equalTo(self.timelineProgress.mas_bottom).with.offset(kMargin);
} else {
make.top.mas_equalTo(bookNameLabel.mas_bottom).with.offset(kMargin);
}
make.width.height.mas_equalTo(bookImageView.mas_width).with.multipliedBy(0.5);
}];
playButtonIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleWhite)];
playButtonIndicator.color = kWhiteColor;
playButtonIndicator.hidesWhenStopped = YES;
[playButton addSubview:playButtonIndicator];
[playButtonIndicator startAnimating];
[playButtonIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(playButton.mas_centerX).with.offset(1);
make.centerY.mas_equalTo(playButton.mas_centerY).with.offset(1);
make.width.height.mas_equalTo(playButton);
}];
previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
previousButton.adjustsImageWhenHighlighted = NO;
previousButton.enabled = NO;
previousButton.tag = 1;
previousButton.touchEventInterval = 0.5;
[previousButton setImage:[UIImage imageNamed:@"audio_previous_unenable"] forState:UIControlStateNormal];
[previousButton addTarget:self action:@selector(skipToLastChapter) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:previousButton];
[previousButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(playButton.mas_centerY);
make.right.mas_equalTo(bookImageView.mas_left).with.offset(- kMargin);
make.width.height.mas_equalTo(playButton.mas_width).with.multipliedBy(0.4);
}];
nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
nextButton.adjustsImageWhenHighlighted = NO;
nextButton.enabled = NO;
nextButton.tag = 2;
nextButton.touchEventInterval = 0.5;
[nextButton setImage:[UIImage imageNamed:@"audio_next_unenable"] forState:UIControlStateNormal];
[nextButton addTarget:self action:@selector(skipToNextChapter) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:nextButton];
[nextButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(playButton.mas_centerY);
make.left.mas_equalTo(bookImageView.mas_right).with.offset(kMargin);
make.width.height.mas_equalTo(previousButton);
}];
CGFloat buttonSpace = (SCREEN_WIDTH - 2 * kMargin - 5 * 80) / 4;
if (self.productionType == TFProductionTypeAudio) {
buttonSpace = (SCREEN_WIDTH - 2 * kMargin - 4 * 80) / 3;
}
self.timingButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"定时") buttonImageName:@"audio_speech_timing" buttonIndicator:TFButtonIndicatorTitleBottom];
self.timingButton.tag = 0;
self.timingButton.buttonTitleFont = kFont10;
self.timingButton.graphicDistance = 5;
self.timingButton.buttonImageScale = 0.5;
[self.timingButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.timingButton];
[self.timingButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMargin);
make.top.mas_equalTo(playButton.mas_bottom).with.offset(kMargin);
make.width.mas_equalTo(80);
make.height.mas_equalTo(50);
}];
self.speedButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"语速") buttonImageName:[NSString stringWithFormat:@"audio_speech_speed%@", [TFUtilsHelper formatStringWithInteger:[[WXYZ_AudioSettingHelper sharedManager] getReadSpeedWithProducitionType:self.productionType]]] buttonIndicator:TFButtonIndicatorTitleBottom];
self.speedButton.tag = 1;
self.speedButton.buttonTitleFont = kFont10;
self.speedButton.graphicDistance = 5;
self.speedButton.buttonImageScale = 0.55;
[self.speedButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.speedButton];
[self.speedButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.timingButton.mas_right).with.offset(buttonSpace);
make.top.mas_equalTo(self.timingButton.mas_top);
make.width.mas_equalTo(self.timingButton.mas_width);
make.height.mas_equalTo(self.timingButton.mas_height);
}];
if (self.productionType == TFProductionTypeAi) {
self.voiceButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString([[WXYZ_AudioSettingHelper sharedManager] getReadVoiceTitleWithProducitionType:TFProductionTypeAi]) buttonImageName:@"audio_speech_tone" buttonIndicator:TFButtonIndicatorTitleBottom];
self.voiceButton.tag = 2;
self.voiceButton.buttonTitleFont = kFont10;
self.voiceButton.graphicDistance = 5;
self.voiceButton.buttonImageScale = 0.5;
[self.voiceButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.voiceButton];
[self.voiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.speedButton.mas_right).with.offset(buttonSpace);
make.top.mas_equalTo(self.timingButton.mas_top);
make.width.mas_equalTo(self.timingButton.mas_width);
make.height.mas_equalTo(self.timingButton.mas_height);
}];
}
chapterButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"目录") buttonImageName:@"audio_speech_catalogue" buttonIndicator:TFButtonIndicatorTitleBottom];
chapterButton.tag = 3;
chapterButton.buttonTitleFont = kFont10;
chapterButton.graphicDistance = 5;
chapterButton.buttonImageScale = 0.5;
[chapterButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:chapterButton];
[chapterButton mas_makeConstraints:^(MASConstraintMaker *make) {
if (self.productionType == TFProductionTypeAudio) {
make.left.mas_equalTo(self.speedButton.mas_right).with.offset(buttonSpace);
} else {
make.left.mas_equalTo(self.voiceButton.mas_right).with.offset(buttonSpace);
}
make.top.mas_equalTo(self.timingButton.mas_top);
make.width.mas_equalTo(self.timingButton.mas_width);
make.height.mas_equalTo(self.timingButton.mas_height);
}];
originalButton = [[TFButton alloc] initWithFrame:CGRectZero buttonTitle:TFLocalizedString(@"原文") buttonImageName:@"audio_speech_original" buttonIndicator:TFButtonIndicatorTitleBottom];
originalButton.tag = 4;
originalButton.buttonTitleFont = kFont10;
originalButton.graphicDistance = 5;
originalButton.buttonImageScale = 0.5;
[originalButton addTarget:self action:@selector(toolBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:originalButton];
[originalButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(chapterButton.mas_right).with.offset(buttonSpace);
make.top.mas_equalTo(self.timingButton.mas_top);
make.width.mas_equalTo(80);
make.height.mas_equalTo(self.timingButton.mas_height);
}];
relationView = [UIButton buttonWithType:UIButtonTypeCustom];
relationView.backgroundColor = kGrayViewColor;
relationView.layer.cornerRadius = 6;
relationView.clipsToBounds = YES;
[relationView addTarget:self action:@selector(relationProductionClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:relationView];
[relationView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kHalfMargin);
make.top.mas_equalTo(originalButton.mas_bottom).with.offset(kMargin);
make.width.mas_equalTo(SCREEN_WIDTH - kMargin);
make.height.mas_equalTo(80);
}];
UIImageView *relationIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"audio_change_to_sound"]];
if (self.productionType == TFProductionTypeAudio) {
relationIcon.image = [UIImage imageNamed:@"audio_change_to_ai"];
}
relationIcon.userInteractionEnabled = YES;
[relationView addSubview:relationIcon];
[relationIcon mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMargin);
make.centerY.mas_equalTo(relationView.mas_centerY);
make.width.height.mas_equalTo(relationView.mas_height).with.multipliedBy(0.5);
}];
UIImageView *connerImage = [[UIImageView alloc] init];
connerImage.image = [UIImage imageNamed:@"public_more"];
[relationView addSubview:connerImage];
[connerImage mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(relationView.mas_right).with.offset(- kMargin);
make.centerY.mas_equalTo(relationView.mas_centerY);
make.width.height.mas_equalTo(10);
}];
UILabel *relationLabel = [[UILabel alloc] init];
relationLabel.text = TFLocalizedString(@"切换到有声阅读");
if (self.productionType == TFProductionTypeAudio) {
relationLabel.text = TFLocalizedString(@"切换到AI语音阅读");
}
relationLabel.textColor = kBlackColor;
relationLabel.textAlignment = NSTextAlignmentLeft;
relationLabel.font = kMainFont;
[relationView addSubview:relationLabel];
[relationLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(relationIcon.mas_right).with.offset(kHalfMargin);
make.right.mas_equalTo(connerImage.mas_left).with.offset(- kHalfMargin);
make.bottom.mas_equalTo(connerImage.mas_centerY);
make.height.mas_equalTo(relationView.mas_height).multipliedBy(0.3);
}];
relationChapterTitle = [[UILabel alloc] init];
relationChapterTitle.textColor = kGrayTextColor;
relationChapterTitle.textAlignment = NSTextAlignmentLeft;
relationChapterTitle.font = kFont10;
[relationView addSubview:relationChapterTitle];
[relationChapterTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(relationIcon.mas_right).with.offset(kHalfMargin);
make.right.mas_equalTo(connerImage.mas_left).with.offset(- kHalfMargin);
make.top.mas_equalTo(connerImage.mas_centerY);
make.height.mas_equalTo(relationView.mas_height).multipliedBy(0.3);
}];
}
- (void)setProductionChapterModel:(TFProductionChapterModel *)productionChapterModel
{
_productionChapterModel = productionChapterModel;
// 封面
[bookImageView resetDefaultHoldImage];
bookImageView.coverImageUrl = productionChapterModel.cover;
// 章节
chapterNameLabel.text = [TFUtilsHelper formatStringWithObject:productionChapterModel.chapter_title?:@""];
// 标题
bookNameLabel.text = [TFUtilsHelper formatStringWithObject:productionChapterModel.name?:@""];
// 设置总音频时长
self.timelineProgress.totalTimeLength = productionChapterModel.duration_second;
// 下一首
if (productionChapterModel.last_chapter > 0 && productionChapterModel.last_chapter) {
[previousButton setImage:[UIImage imageNamed:@"audio_previous_enable"] forState:UIControlStateNormal];
previousButton.enabled = YES;
} else {
[previousButton setImage:[UIImage imageNamed:@"audio_previous_unenable"] forState:UIControlStateNormal];
previousButton.enabled = NO;
}
// 上一首
if (productionChapterModel.next_chapter > 0 && productionChapterModel.next_chapter) {
[nextButton setImage:[UIImage imageNamed:@"audio_next_enable"] forState:UIControlStateNormal];
nextButton.enabled = YES;
} else {
[nextButton setImage:[UIImage imageNamed:@"audio_next_unenable"] forState:UIControlStateNormal];
nextButton.enabled = NO;
}
[self layoutIfNeeded];
}
- (void)setRelationModel:(WXYZ_RelationModel *)relationModel
{
_relationModel = relationModel;
// 更新关联作品章节标题
relationChapterTitle.text = [[TFReadRecordManager shareManagerWithProductionType:(self.productionType == TFProductionTypeAudio?TFProductionTypeAi:TFProductionTypeAudio)] getReadingRecordChapterTitleWithProduction_id:relationModel.production_id]?:relationModel.chapter_title?:@"";
if (self.productionType == TFProductionTypeAudio) {
if (relationModel.production_id > 0) {
relationView.hidden = NO;
originalButton.hidden = NO;
CGFloat buttonSpace = (SCREEN_WIDTH - 2 * kMargin - 4 * 80) / 3;
[self.timingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(kMargin);
}];
[self.speedButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.timingButton.mas_right).with.offset(buttonSpace);
}];
[chapterButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.speedButton.mas_right).with.offset(buttonSpace);
}];
if ([TFUtilsHelper getAiReadSwitchState]) {
[relationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(80);
}];
} else {
[relationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(CGFLOAT_MIN);
}];
}
} else {
relationView.hidden = YES;
originalButton.hidden = YES;
CGFloat buttonSpace = (SCREEN_WIDTH - 4 * kMargin - 3 * 80) / 2;
[self.timingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(2 * kMargin);
}];
[self.speedButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.timingButton.mas_right).with.offset(buttonSpace);
}];
[chapterButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.speedButton.mas_right).with.offset(buttonSpace);
}];
[relationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(CGFLOAT_MIN);
}];
}
} else {
if (relationModel.production_id > 0 && [TFUtilsHelper getAiReadSwitchState]) {
relationView.hidden = NO;
[relationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(80);
}];
} else {
relationView.hidden = YES;
[relationView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(CGFLOAT_MIN);
}];
}
}
[self layoutIfNeeded];
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.frame = CGRectMake(0, 0, SCREEN_WIDTH, relationView.bottom + kHalfMargin);
}
// 设置关联作品标题
- (void)setRelationViewTitle:(NSString *)title
{
// 更新关联作品章节标题
relationChapterTitle.text = title;
}
#pragma mark - CKAudioProgressViewDelegate
// 拖动进度条
- (void)audioProgresstouchEndhCurrentTime:(NSInteger)currentTime totalTime:(NSInteger)totalTime
{
if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStateStoped) {
return;
}
self.playerState = TFBasicVoicePlayerStateLoading;
[[WXYZ_Player sharedPlayer] seekToTime:(float)currentTime / totalTime completionBlock:^{
}];
}
#pragma mark - 点击事件
- (void)playButtonClick
{
if (self.productionChapterModel.is_preview == 1 && ![TFUserInfoManager shareInstance].auto_sub) {
[self showPayView];
return;
}
if ([TFNetworkManager networkingStatus] == NO && ![[WXYZ_AudioDownloadManager sharedManager] isChapterDownloadedWithProduction_id:self.productionChapterModel.production_id chapter_id:self.productionChapterModel.chapter_id]) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"当前为离线状态,只可查看缓存内容哦")];
return;
}
if (self.productionType == TFProductionTypeAi) {
[[WXYZ_Player sharedPlayer] pause];
if (self.playerState == TFBasicVoicePlayerStatePlaying) {
[[IFlySpeechSynthesizer sharedInstance] pauseSpeaking];
} else {
[[IFlySpeechSynthesizer sharedInstance] resumeSpeaking];
if (self.resetPlayerBlock) {
self.resetPlayerBlock(NO);
}
}
} else {
[[IFlySpeechSynthesizer sharedInstance] pauseSpeaking];
if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying) {
[[WXYZ_Player sharedPlayer] pause];
self.playerState = TFBasicVoicePlayerStatePause;
} else if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePause) {
[[WXYZ_Player sharedPlayer] play];
self.playerState = TFBasicVoicePlayerStatePlaying;
if ([WXYZ_BookAiPlayPageViewController sharedManager].speaking) {
[[IFlySpeechSynthesizer sharedInstance] pauseSpeaking];
}
} else if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStateStoped) {
[[WXYZ_Player sharedPlayer] reloadData]; // 需在传入数据源后调用
[[WXYZ_Player sharedPlayer] playWithAudioId:0];
} else if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStateFail) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"播放出错")];
}
}
}
- (void)skipToLastChapter
{
self.playerState = TFBasicVoicePlayerStateLoading;
NSInteger skipChapter_id = 0;
if (self.productionChapterModel.last_chapter > 0) {
skipChapter_id = self.productionChapterModel.last_chapter;
}
if (skipChapter_id == 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"章节正在更新中")];
return;
}
if (self.productionType == TFProductionTypeAi) {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_AiBook_Chapter object:[TFUtilsHelper formatStringWithInteger:skipChapter_id]];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Audio_Chapter object:[TFUtilsHelper formatStringWithInteger:skipChapter_id]];
}
}
- (void)skipToNextChapter
{
self.playerState = TFBasicVoicePlayerStateLoading;
NSInteger skipChapter_id = 0;
if (self.productionChapterModel.next_chapter > 0) {
skipChapter_id = self.productionChapterModel.next_chapter;
}
if (skipChapter_id == 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"章节正在更新中")];
return;
}
if (self.productionType == TFProductionTypeAi) {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_AiBook_Chapter object:[TFUtilsHelper formatStringWithInteger:skipChapter_id]];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Audio_Chapter object:[TFUtilsHelper formatStringWithInteger:skipChapter_id]];
}
}
- (void)relationProductionClick
{
if ([TFUtilsHelper getAiReadSwitchState]) {
if (self.checkRelationProductionBlock) {
self.checkRelationProductionBlock(self.relationModel);
}
}
}
// 快进或快退
- (void)adjustProgress:(UIButton *)sender
{
sender.enabled = NO;
CGFloat valuePercentage = 0;
CGFloat currentTime = [[WXYZ_Player sharedPlayer] currentTime];
CGFloat totalTime = [[WXYZ_Player sharedPlayer] totalTime];
if (sender.tag == 0) { // 快进
if (currentTime + 15 > totalTime) {
valuePercentage = 1;
} else {
valuePercentage = (currentTime + 15) / totalTime;
}
} else { // 快退
if (currentTime - 15 > 0) {
valuePercentage = (currentTime - 15) / totalTime;
}
}
[[WXYZ_Player sharedPlayer] seekToTime:valuePercentage completionBlock:^{
sender.enabled = YES;
}];
[self.timelineProgress updateProgress:valuePercentage audioLength:totalTime];
}
- (void)toolBarButtonClick:(UIButton *)sender
{
if (sender.tag == 4) {
if (self.productionType == TFProductionTypeAi) {
[[TFReaderSettingHelper sharedManager] setLocationMemoryOfChapterIndex:[self.productionChapterModel.display_order integerValue] pagerIndex:0 book_id:self.productionChapterModel.production_id];
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Retry_Chapter object:@"1"];
}
if (self.checkOriginalBlock) {
self.checkOriginalBlock(self.productionChapterModel);
}
return;
}
WS(weakSelf)
WXYZ_AudioPlayPageMenuView *playPageMenuView = [[WXYZ_AudioPlayPageMenuView alloc] init];
switch (sender.tag) {
case 0:
[playPageMenuView showWithMenuType:WXYZ_MenuTypeTiming];
break;
case 1:
if (self.productionType == TFProductionTypeAudio) {
[playPageMenuView showWithMenuType:WXYZ_MenuTypeAudioSpeed];
} else {
[playPageMenuView showWithMenuType:WXYZ_MenuTypeAiSpeed];
}
break;
case 2:
[playPageMenuView showWithMenuType:WXYZ_MenuTypeAiVoice];
break;
case 3:
playPageMenuView.menuListArray = self.chapter_list;
if (self.chapter_list.firstObject.total_chapters != 0) {
playPageMenuView.totalChapter = self.chapter_list.firstObject.total_chapters;
} else {
playPageMenuView.totalChapter = self.chapter_list.count;
}
if (self.productionType == TFProductionTypeAudio) {
[playPageMenuView showWithMenuType:WXYZ_MenuTypeAudioDirectory];
} else {
[playPageMenuView showWithMenuType:WXYZ_MenuTypeAiDirectory];
}
break;
default:
break;
}
playPageMenuView.chooseMenuBlock = ^(WXYZ_MenuType menuType, NSInteger chooseIndex) {
switch (menuType) {
case WXYZ_MenuTypeTiming:
{
SS(strongSelf)
[[WXYZ_AudioSettingHelper sharedManager] startTimingFinishBlock:^{
if ([[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == 1) {
strongSelf.timingButton.buttonTitle = TFLocalizedString(@"听完本章节");
} else if ([[WXYZ_AudioSettingHelper sharedManager] getReadTiming] == 0) {
strongSelf.timingButton.buttonTitle = TFLocalizedString(@"定时");
}
}];
}
break;
case WXYZ_MenuTypeAiSpeed:
case WXYZ_MenuTypeAudioSpeed:
weakSelf.speedButton.buttonImageName = [NSString stringWithFormat:@"audio_speech_speed%@", [TFUtilsHelper formatStringWithInteger:chooseIndex]];
if (weakSelf.productionType == TFProductionTypeAudio) {
[[WXYZ_Player sharedPlayer] setRate:[[[[WXYZ_AudioSettingHelper sharedManager] getReadSpeedValuesWithProducitionType:weakSelf.productionType] objectAtIndex:[[WXYZ_AudioSettingHelper sharedManager] getReadSpeedWithProducitionType:weakSelf.productionType]] floatValue]];
} else {
if (weakSelf.resetPlayerBlock) {
weakSelf.resetPlayerBlock(YES);
}
}
break;
case WXYZ_MenuTypeAiVoice:
self.voiceButton.buttonTitle = TFLocalizedString([[WXYZ_AudioSettingHelper sharedManager] getReadVoiceTitleWithProducitionType:TFProductionTypeAi]);
if (weakSelf.resetPlayerBlock) {
weakSelf.resetPlayerBlock(YES);
}
break;
default:
break;
}
};
playPageMenuView.chooseDirectoryMenuBlock = ^(NSInteger chapter_id, NSInteger chooseIndex) {
if (weakSelf.productionType == TFProductionTypeAudio) {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Audio_Chapter object:[TFUtilsHelper formatStringWithInteger:chapter_id]];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_AiBook_Chapter object:[TFUtilsHelper formatStringWithInteger:chapter_id]];
}
};
}
- (void)resetPlayerInfo
{
self.temp_chapterModel = [[TFProductionChapterModel alloc] init];
}
- (void)showPayView
{
if (![[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAi] && ![[WXYZ_AudioSettingHelper sharedManager] isPlayPageShowingWithProductionType:TFProductionTypeAudio]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"听到付费章节啦")];
});
return;
}
WS(weakSelf)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
WXYZ_ChapterBottomPayBar *payBar = [[WXYZ_ChapterBottomPayBar alloc] initWithChapterModel:self.productionChapterModel barType:WXYZ_BottomPayBarTypeBuyChapter productionType:self.productionType];
payBar.paySuccessChaptersBlock = ^(NSArray<NSString *> * _Nonnull success_chapter_ids) {
if (weakSelf.productionType == TFProductionTypeAi) {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_AiBook_Chapter object:[TFUtilsHelper formatStringWithInteger:weakSelf.productionChapterModel.chapter_id] userInfo:@{@"success_chapter_ids":success_chapter_ids}];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Audio_Chapter object:[TFUtilsHelper formatStringWithInteger:weakSelf.productionChapterModel.chapter_id]];
}
};
[payBar showBottomPayBar];
});
}
- (void)setPlayerState:(TFBasicVoicePlayerState)playerState
{
if (self) {
_playerState = playerState;
dispatch_async(dispatch_get_main_queue(), ^{
switch (playerState) {
case TFBasicVoicePlayerStateLoading:
fastForwardButton.enabled = NO;
fastBackButton.enabled = NO;
playButton.enabled = NO;
[playButton setImage:[UIImage imageNamed:@"audio_play_loading"] forState:UIControlStateNormal];
[playButtonIndicator startAnimating];
break;
case TFBasicVoicePlayerStatePlaying:
fastForwardButton.enabled = YES;
fastBackButton.enabled = YES;
playButton.enabled = YES;
[playButton setImage:[UIImage imageNamed:@"audio_suspended"] forState:UIControlStateNormal];
[playButtonIndicator stopAnimating];
self.timelineProgress.userInteractionEnabled = YES;
[[WXYZ_TouchAssistantView sharedManager] playPlayerState];
if (self.productionType == TFProductionTypeAudio && [[WXYZ_Player sharedPlayer] progress] == 0) {
[self.timelineProgress updateProgress:0 audioLength:[[WXYZ_Player sharedPlayer] totalTime]];
}
break;
case TFBasicVoicePlayerStatePause:
fastForwardButton.enabled = YES;
fastBackButton.enabled = YES;
playButton.enabled = YES;
[playButton setImage:[UIImage imageNamed:@"audio_play"] forState:UIControlStateNormal];
[playButtonIndicator stopAnimating];
[[WXYZ_TouchAssistantView sharedManager] pausePlayerState];
break;
case TFBasicVoicePlayerStateFail:
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:TFLocalizedString(@"播放出错")];
case TFBasicVoicePlayerStateStoped:
fastForwardButton.enabled = NO;
fastBackButton.enabled = NO;
playButton.enabled = YES;
[playButton setImage:[UIImage imageNamed:@"audio_play"] forState:UIControlStateNormal];
[playButtonIndicator stopAnimating];
[[WXYZ_TouchAssistantView sharedManager] stopPlayerState];
[self.timelineProgress updateCacheProgress:0];
[self.timelineProgress updateProgress:0 audioLength:0];
break;
default:
break;
}
});
}
}
@end
@@ -0,0 +1,39 @@
//
// WXYZ_PlayPageModel.h
// WXReader
//
// Created by Andrew on 2020/3/10.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFCommentsListModel, TFAdvertModel, WXYZ_RelationModel;
@interface WXYZ_PlayPageModel : NSObject
@property (nonatomic, assign) NSInteger comment_total_count;
@property (nonatomic, strong) TFCommentsModel *comment;
@property (nonatomic, strong) NSArray <TFProductionModel *> *list;
@property (nonatomic, strong) WXYZ_RelationModel *relation;
@property (nonatomic, strong) TFAdvertModel *advert;
@end
@interface WXYZ_RelationModel : NSObject
@property (nonatomic, assign) NSInteger production_id;
@property (nonatomic, assign) NSInteger chapter_id;
@property (nonatomic, copy) NSString *chapter_title;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,31 @@
//
// WXYZ_PlayPageModel.m
// WXReader
//
// Created by Andrew on 2020/3/10.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_PlayPageModel.h"
@implementation WXYZ_PlayPageModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass{
return @{@"comment" : [TFCommentsModel class],
@"list" : [TFProductionModel class],
@"advert" : [TFAdvertModel class],
@"relation" : [WXYZ_RelationModel class]
};
}
@end
@implementation WXYZ_RelationModel
+ (NSDictionary *)modelCustomPropertyMapper {
return @{
@"production_id" :@[@"book_id", @"comic_id", @"audio_id"]
};
}
@end
@@ -0,0 +1,254 @@
//
// WXYZ_Player.h
// WXYZ_Player
//
// Created by ihoudf on 2017/7/18.
// Copyright © 2017年 ihoudf. All rights reserved.
//
//
// WXYZ_Player当前版本:2.0.2
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import "WXYZ_PlayerModel.h"
#import "TFBasicVoiceHeaderView.h"
//播放模式
typedef NS_ENUM(NSInteger, WXYZ_PlayerMode){
WXYZ_PlayerModeOnlyOnce, //单曲只播放一次,默认
WXYZ_PlayerModeSingleCycle, //单曲循环
WXYZ_PlayerModeOrderCycle, //顺序循环
WXYZ_PlayerModeShuffleCycle //随机循环
};
@class WXYZ_Player;
@protocol WXYZ_PlayerDataSource <NSObject>
@required
/**
数据源1:音频数组
@param player WXYZ_Player
*/
- (NSArray<WXYZ_PlayerModel *> *)audioDataForPlayer:(WXYZ_Player *)player;
@optional
/**
数据源2:音频信息
调用playWithAudioId时,WXYZ_Player会调用此方法请求当前音频的信息
根据player.currentAudioModel.audioId获取音频在数组中的位置,传入对应的音频信息model
@param player WXYZ_Player
*/
- (WXYZ_PlayerInfoModel *)audioInfoForPlayer:(WXYZ_Player *)player;
@end
@protocol WXYZ_PlayerDelegate <NSObject>
@optional
/**
代理1:音频已经加入播放队列
@param player WXYZ_Player
*/
- (void)playerAudioAddToPlayQueue:(WXYZ_Player *)player;
/**
代理2:准备播放
@param player WXYZ_Player
*/
- (void)playerReadyToPlay:(WXYZ_Player *)player;
/**
代理3:缓冲进度代理 (属性isObserveBufferProgress(默认YES)为YES时有效)
@param player WXYZ_Player
@param bufferProgress 缓冲进度
*/
- (void)player:(WXYZ_Player *)player bufferProgress:(CGFloat)bufferProgress;
/**
代理4:播放进度代理 (属性isObserveProgress(默认YES)为YES时有效)
@param player WXYZ_Player
@param progress 播放进度
@param currentTime 当前播放到的时间
*/
- (void)player:(WXYZ_Player *)player progress:(CGFloat)progress currentTime:(CGFloat)currentTime totalTime:(CGFloat)totalTime;
/**
代理5:播放结束代理
(默认播放结束后调用next,如果实现此代理,播放结束逻辑由您处理)
@param player FPlayer
*/
- (void)playerDidPlayToEndTime:(WXYZ_Player *)player;
/**
代理7:播放器被系统打断代理
(默认被系统打断暂停播放,打断结束检测能够播放则恢复播放,如果实现此代理,打断逻辑由您处理)
@param player WXYZ_Player
@param isInterrupted YES:被系统打断开始 NO:被系统打断结束
*/
- (void)player:(WXYZ_Player *)player isInterrupted:(BOOL)isInterrupted;
/**
代理8:监听耳机插入拔出代理
@param player WXYZ_Player
@param isHeadphone YES:插入 NO:拔出
*/
- (void)player:(WXYZ_Player *)player isHeadphone:(BOOL)isHeadphone;
/**
代理9:播放状态改变
*/
- (void)playerStateChange:(TFBasicVoicePlayerState)playerState;
// 远程控制切换上一首作品
- (void)audioPlayerRemoteCenterSwitchToPrevious;
// 远程控制切换下一首作品
- (void)audioPlayerRemoteCenterSwitchToNext;
@end
/**
WXYZ_Player播放管理器
*/
@interface WXYZ_Player : NSObject
#pragma mark - 初始化和操作
@property (nonatomic, weak) id<WXYZ_PlayerDataSource> dataSource;
@property (nonatomic, weak) id<WXYZ_PlayerDelegate> delegate;
// 是否禁止上一首远程控制键可用
@property (nonatomic, assign) BOOL remoteCenterPreviousEnable;
// 是否禁止下一首远程控制键可用
@property (nonatomic, assign) BOOL remoteCenterNextEnable;
/**
播放模式,默认WXYZ_PlayerModeOnlyOnce。
*/
@property (nonatomic, assign) WXYZ_PlayerMode playMode;
/**
播放倍速
*/
@property (nonatomic, assign) CGFloat playRate;
/**
单例
*/
+ (WXYZ_Player *)sharedPlayer;
/**
初始化播放器
*/
- (void)initPlayerWithUserId:(NSString *)userId;
/**
刷新数据源数据
*/
- (void)reloadData;
/**
选择audioId对应的音频开始播放。
说明:WXYZ_Player通过数据源方法提前获取数据,通过playWithAudioId选择对应音频播放。
而在删除、增加音频后需要调用[[WXYZ_Player shareInstance] reloadData];刷新数据。
*/
- (void)playWithAudioId:(NSUInteger)audioId;
/**
播放
*/
- (void)play;
/**
暂停
*/
- (void)pause;
/**
下一首
*/
- (void)next;
/**
上一首
*/
- (void)last;
/**
音频跳转
@param value 时间百分比
@param completionBlock seek结束
*/
- (void)seekToTime:(CGFloat)value completionBlock:(void(^)(void))completionBlock;
/**
倍速播放(iOS10之后系统支持的倍速常数有0.50, 0.67, 0.80, 1.0, 1.25, 1.50和2.0
@param rate 倍速
*/
- (void)setRate:(CGFloat)rate;
/**
释放播放器,还原其他播放器
*/
- (void)deallocPlayer;
#pragma mark - 状态类
/**
播放器状态
*/
@property (nonatomic, readonly, assign) TFBasicVoicePlayerState state;
/**
当前正在播放的音频model
*/
@property (nonatomic, readonly, strong) WXYZ_PlayerModel *currentAudioModel;
/**
当前正在播放的音频信息model
*/
@property (nonatomic, readonly, strong) WXYZ_PlayerInfoModel *currentAudioInfoModel;
/**
当前音频缓冲进度
*/
@property (nonatomic, readonly, assign) CGFloat bufferProgress;
/**
当前音频播放进度
*/
@property (nonatomic, readonly, assign) CGFloat progress;
/**
当前音频当前时间
*/
@property (nonatomic, readonly, assign) CGFloat currentTime;
/**
当前音频总时长
*/
@property (nonatomic, readonly, assign) CGFloat totalTime;
@end
@@ -0,0 +1,628 @@
//
// WXYZ_Player.m
// WXYZ_Player
//
// Created by ihoudf on 2017/7/18.
// Copyright © 2017年 ihoudf. All rights reserved.
//
#import "WXYZ_Player.h"
#import <MediaPlayer/MediaPlayer.h>
#import "WXYZ_TouchAssistantView.h"
#define WXYZ_PlayerHighGlobalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define WXYZ_PlayerDefaultGlobalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
/**Asset KEY*/
NSString * const WXYZPlayableKey = @"playable";
/**PlayerItem KEY*/
NSString * const WXYZStatusKey = @"status";
NSString * const WXYZLoadedTimeRangesKey = @"loadedTimeRanges";
NSString * const WXYZPlaybackBufferEmptyKey = @"playbackBufferEmpty";
NSString * const WXYZPlaybackLikelyToKeepUpKey = @"playbackLikelyToKeepUp";
@interface WXYZ_Player()
{
BOOL _isOtherPlaying; // 其他应用是否正在播放
BOOL _isBackground; // 是否进入后台
BOOL _isSeek; // 正在seek
BOOL _isNaturalToEndTime; // 是否是自然结束
dispatch_group_t _netGroupQueue; // 组队列-网络
dispatch_group_t _dataGroupQueue; // 组队列-数据
CGFloat _seekValue; // seek value
NSMutableDictionary *_remoteInfoDictionary;//控制中心信息
}
/** player */
@property (nonatomic, strong) AVPlayer *player;
/** playerItem */
@property (nonatomic, strong) AVPlayerItem *playerItem;
/** 播放进度监测 */
@property (nonatomic, strong) id timeObserver;
/** model数据数组 */
@property (nonatomic, strong) NSMutableArray<WXYZ_PlayerModel *> *playerModelArray;
@property (nonatomic, copy) void(^seekCompletionBlock)(void);
@property (nonatomic, assign) UIBackgroundTaskIdentifier bgTaskId;
@property (nonatomic, readwrite, strong) WXYZ_PlayerModel *currentAudioModel;
@property (nonatomic, readwrite, strong) WXYZ_PlayerInfoModel *currentAudioInfoModel;
@property (nonatomic, readwrite, assign) TFBasicVoicePlayerState state;
@property (nonatomic, readwrite, assign) CGFloat bufferProgress;
@property (nonatomic, readwrite, assign) CGFloat progress;
@property (nonatomic, readwrite, assign) CGFloat currentTime;
@property (nonatomic, readwrite, assign) CGFloat totalTime;
@end
@implementation WXYZ_Player
#pragma mark - 初始化
+ (WXYZ_Player *)sharedPlayer {
static WXYZ_Player *player = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
player = [[[self class] alloc] init];
});
return player;
}
- (void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
UIBackgroundTaskIdentifier taskID = [[UIApplication sharedExtensionApplication] beginBackgroundTaskWithExpirationHandler:^{}];
if (taskID != UIBackgroundTaskInvalid) {
[[UIApplication sharedExtensionApplication] endBackgroundTask:taskID];
}
}
#pragma mark - 初始化播放器
- (void)initPlayerWithUserId:(NSString *)userId{
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
_isOtherPlaying = [AVAudioSession sharedInstance].otherAudioPlaying;
self.playMode = WXYZ_PlayerModeOnlyOnce;
self.state = TFBasicVoicePlayerStateStoped;
_isBackground = NO;
_netGroupQueue = dispatch_group_create();
_dataGroupQueue = dispatch_group_create();
[self addPlayerObserver];
[self addRemoteControlHandler];
}
- (void)addPlayerObserver{
//将要进入后台
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(playerWillResignActive)
name:UIApplicationWillResignActiveNotification
object:nil];
//已经进入前台
[notificationCenter addObserver:self
selector:@selector(playerDidEnterForeground)
name:UIApplicationDidBecomeActiveNotification
object:nil];
//监测耳机
[notificationCenter addObserver:self
selector:@selector(playerAudioRouteChange:)
name:AVAudioSessionRouteChangeNotification
object:nil];
//监听播放器被打断(别的软件播放音乐,来电话)
[notificationCenter addObserver:self
selector:@selector(playerAudioBeInterrupted:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
}
- (void)playerWillResignActive{
_isBackground = YES;
_bgTaskId = [self backgroundPlayerID:_bgTaskId];
}
- (UIBackgroundTaskIdentifier)backgroundPlayerID:(UIBackgroundTaskIdentifier)backTaskId {
// 设置并激活音频会话类别
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
// 允许应用程序接收远程控制
// 设置后台任务ID
UIBackgroundTaskIdentifier taskId = UIBackgroundTaskInvalid;
taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
if(taskId != UIBackgroundTaskInvalid &&
backTaskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:backTaskId];
}
return taskId;
}
- (void)playerDidEnterForeground{
_isBackground = NO;
}
- (void)playerAudioRouteChange:(NSNotification *)notification{
NSInteger routeChangeReason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] integerValue];
switch (routeChangeReason) {
case AVAudioSessionRouteChangeReasonNewDeviceAvailable://耳机插入
if (self.delegate && [self.delegate respondsToSelector:@selector(player:isHeadphone:)]) {
[self.delegate player:self isHeadphone:YES];
}
break;
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable://耳机拔出,停止播放操作
if (self.delegate && [self.delegate respondsToSelector:@selector(player:isHeadphone:)]) {
[self.delegate player:self isHeadphone:NO];
}else{
[self pause];
}
break;
case AVAudioSessionRouteChangeReasonCategoryChange:
//
break;
default:
break;
}
}
- (void)playerAudioBeInterrupted:(NSNotification *)notification{
NSDictionary *dic = notification.userInfo;
if ([dic[AVAudioSessionInterruptionTypeKey] integerValue] == 1) {//打断开始
if (self.delegate && [self.delegate respondsToSelector:@selector(player:isInterrupted:)]) {
[self.delegate player:self isInterrupted:YES];
}else{
[self pause];
}
}else {//打断结束
if (self.delegate && [self.delegate respondsToSelector:@selector(player:isInterrupted:)]) {
[self.delegate player:self isInterrupted:NO];
}else{
if ([notification.userInfo[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == 1) {
[self play];
}
}
}
}
-(void)playerDidPlayToEndTime:(NSNotification *)notification{
// 其他音视频播放结束也会触发回调,例如穿山甲的激励视频。
if (notification.object != self.playerItem) return;
if (self.delegate && [self.delegate respondsToSelector:@selector(playerDidPlayToEndTime:)]) {
[self.delegate playerDidPlayToEndTime:self];
}else{
_isNaturalToEndTime = YES;
[self next];
}
}
/**远程线控*/
- (void)addRemoteControlHandler
{
if (@available (iOS 7.1, *)) {
kCodeSync([[UIApplication sharedApplication] endReceivingRemoteControlEvents]);
kCodeSync([[UIApplication sharedApplication] beginReceivingRemoteControlEvents]);
MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
[self addRemoteCommand:center.playCommand selector:@selector(play)];
[self addRemoteCommand:center.pauseCommand selector:@selector(pause)];
[self addRemoteCommand:center.previousTrackCommand selector:@selector(last)];
[self addRemoteCommand:center.nextTrackCommand selector:@selector(next)];
[center.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
if ([WXYZ_Player sharedPlayer].state == TFBasicVoicePlayerStatePlaying) {
[[WXYZ_Player sharedPlayer] pause];
}else{
[[WXYZ_Player sharedPlayer] play];
}
return MPRemoteCommandHandlerStatusSuccess;
}];
if (@available (iOS 9.1,*)) {
[center.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
MPChangePlaybackPositionCommandEvent *positionEvent = (MPChangePlaybackPositionCommandEvent *)event;
if (self.totalTime > 0) {
[self seekToTime:positionEvent.positionTime / self.totalTime completionBlock:nil];
}
return MPRemoteCommandHandlerStatusSuccess;
}];
}
}
}
- (void)addRemoteCommand:(MPRemoteCommand *)command selector:(SEL)selector{
[command addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
if ([self respondsToSelector:selector]) {
IMP imp = [self methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(self, selector);
}
return MPRemoteCommandHandlerStatusSuccess;
}];
}
- (void)setRemoteCenterPreviousEnable:(BOOL)remoteCenterPreviousEnable
{
_remoteCenterPreviousEnable = remoteCenterPreviousEnable;
[MPRemoteCommandCenter sharedCommandCenter].previousTrackCommand.enabled = remoteCenterPreviousEnable;
}
- (void)setRemoteCenterNextEnable:(BOOL)remoteCenterNextEnable
{
_remoteCenterNextEnable = remoteCenterNextEnable;
[MPRemoteCommandCenter sharedCommandCenter].nextTrackCommand.enabled = remoteCenterNextEnable;
}
#pragma mark - 数据源
- (void)reloadData{
if (self.dataSource && [self.dataSource respondsToSelector:@selector(audioDataForPlayer:)]) {
if (!self.playerModelArray) {
self.playerModelArray = [NSMutableArray array];
}
if (self.playerModelArray.count != 0) {
[self.playerModelArray removeAllObjects];
}
dispatch_group_enter(_dataGroupQueue);
dispatch_group_async(_dataGroupQueue, WXYZ_PlayerHighGlobalQueue, ^{
dispatch_async(WXYZ_PlayerHighGlobalQueue, ^{
[self.playerModelArray addObjectsFromArray:[self.dataSource audioDataForPlayer:self]];
//更新currentAudioId
if (self.currentAudioModel.audioUrl) {
[self.playerModelArray enumerateObjectsWithOptions:(NSEnumerationConcurrent) usingBlock:^(WXYZ_PlayerModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj.audioUrl.absoluteString isEqualToString:self.currentAudioModel.audioUrl.absoluteString]) {
self.currentAudioModel.audioId = idx;
*stop = YES;
}
}];
}
dispatch_group_leave(self->_dataGroupQueue);
});
});
}
}
#pragma mark - 播放 IMPORTANT
- (void)playWithAudioId:(NSUInteger)audioId{
dispatch_group_notify(_dataGroupQueue, WXYZ_PlayerHighGlobalQueue, ^{
if (self.playerModelArray.count > audioId) {
self.currentAudioModel = self.playerModelArray[audioId];
[self audioPrePlay];
}
});
}
- (void)audioPrePlay{
[self reset];
if (self.dataSource && [self.dataSource respondsToSelector:@selector(audioInfoForPlayer:)]) {
self.currentAudioInfoModel = [self.dataSource audioInfoForPlayer:self];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(playerAudioAddToPlayQueue:)]) {
[self.delegate playerAudioAddToPlayQueue:self];
}
[self loadPlayerItemWithURL:self.currentAudioModel.audioUrl];
}
- (void)loadPlayerItemWithURL:(NSURL *)URL{
self.playerItem = [[AVPlayerItem alloc] initWithURL:URL];
[self loadPlayer];
}
- (void)loadPlayerItemWithAsset:(AVURLAsset *)asset{
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self loadPlayer];
}
- (void)loadPlayer{
self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];
if (@available(iOS 10.0,*)) {
self.player.automaticallyWaitsToMinimizeStalling = NO;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 处理章节开始播放,但监听还未执行的问题
[self play];
});
[self addProgressObserver];
[self addPlayingCenterInfo];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if (object == self.player.currentItem) {
if ([keyPath isEqualToString:WXYZStatusKey]) {
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
switch (status) {
case AVPlayerItemStatusUnknown:
self.state = TFBasicVoicePlayerStateStoped;
if (self.delegate && [self.delegate respondsToSelector:@selector(playerStateChange:)]) {
[self.delegate playerStateChange:self.state];
}
break;
case AVPlayerItemStatusReadyToPlay:
if (self.delegate && [self.delegate respondsToSelector:@selector(playerReadyToPlay:)]) {
if (self.state != TFBasicVoicePlayerStatePause) {
[self.delegate playerReadyToPlay:self];
}
}
break;
case AVPlayerItemStatusFailed:
self.state = TFBasicVoicePlayerStateFail;
if (self.delegate && [self.delegate respondsToSelector:@selector(playerStateChange:)]) {
[self.delegate playerStateChange:self.state];
}
break;
default:
break;
}
} else if ([keyPath isEqualToString:WXYZLoadedTimeRangesKey]) {
[self addBufferProgressObserver];
} else if ([keyPath isEqualToString:WXYZPlaybackBufferEmptyKey]) {
} else if ([keyPath isEqualToString:WXYZPlaybackLikelyToKeepUpKey]) {
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - 缓冲进度 播放进度 歌曲锁屏信息 音频跳转
- (void)addBufferProgressObserver{
self.totalTime = CMTimeGetSeconds(self.playerItem.asset.duration);
CMTimeRange timeRange = [self.playerItem.loadedTimeRanges.firstObject CMTimeRangeValue];
CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
if (self.totalTime != 0) {//避免出现inf
self.bufferProgress = (startSeconds + durationSeconds) / self.totalTime;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(player:bufferProgress:)]) {
[self.delegate player:self bufferProgress:self.bufferProgress];
}
}
- (void)addProgressObserver
{
WS(weakSelf)
self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0, 1.0) queue:nil usingBlock:^(CMTime time){
SS(sSelf)
AVPlayerItem *currentItem = sSelf.playerItem;
NSArray *loadedRanges = currentItem.seekableTimeRanges;
if (loadedRanges.count > 0 && currentItem.duration.timescale != 0){
if (sSelf.state != TFBasicVoicePlayerStatePlaying && sSelf.state != TFBasicVoicePlayerStatePause) {
sSelf.state = TFBasicVoicePlayerStatePlaying;
if (sSelf.delegate && [sSelf.delegate respondsToSelector:@selector(playerStateChange:)]) {
[sSelf.delegate playerStateChange:sSelf.state];
}
}
CGFloat currentT = (CGFloat)CMTimeGetSeconds(time);
sSelf.currentTime = currentT + (sSelf.totalTime > 1?1:0);
if (sSelf.totalTime != 0 && !isnan(sSelf.totalTime)) {// 避免出现inf
sSelf.progress = (CMTimeGetSeconds([currentItem currentTime]) + (sSelf.totalTime > 1?1:0)) / sSelf.totalTime;
}
if (sSelf.delegate && [sSelf.delegate respondsToSelector:@selector(player:progress:currentTime:totalTime:)]) {
[sSelf.delegate player:sSelf progress:sSelf.progress currentTime:currentT totalTime:sSelf.totalTime];
}
[sSelf updatePlayingCenterInfo];
}
}];
}
- (void)addPlayingCenterInfo{
_remoteInfoDictionary = [NSMutableDictionary dictionary];
if (self.currentAudioInfoModel.audioName) {
_remoteInfoDictionary[MPMediaItemPropertyTitle] = self.currentAudioInfoModel.audioName;
}
if (self.currentAudioInfoModel.audioAlbum) {
_remoteInfoDictionary[MPMediaItemPropertyAlbumTitle] = self.currentAudioInfoModel.audioAlbum;
}
if (self.currentAudioInfoModel.audioSinger) {
_remoteInfoDictionary[MPMediaItemPropertyArtist] = self.currentAudioInfoModel.audioSinger;
}
if ([self.currentAudioInfoModel.audioImage isKindOfClass:[UIImage class]] && self.currentAudioInfoModel.audioImage) {
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:CGSizeMake(BOOK_WIDTH, BOOK_HEIGHT) requestHandler:^UIImage * _Nonnull(CGSize size) {
return self.currentAudioInfoModel.audioImage;
}];
_remoteInfoDictionary[MPMediaItemPropertyArtwork] = artwork;
}
_remoteInfoDictionary[MPNowPlayingInfoPropertyPlaybackRate] = [NSNumber numberWithFloat:1.0];
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = _remoteInfoDictionary;
}
- (void)updatePlayingCenterInfo{
if (!_isBackground) {return;}
if ([WXYZ_TouchAssistantView sharedManager].productionType == TFProductionTypeAudio) {
_remoteInfoDictionary[MPNowPlayingInfoPropertyElapsedPlaybackTime] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.currentTime)];
_remoteInfoDictionary[MPMediaItemPropertyPlaybackDuration] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.duration)];
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = _remoteInfoDictionary;
}
}
- (void)seekToTime:(CGFloat)value completionBlock:(void (^)(void))completionBlock{
_isSeek = YES;
// 先暂停
BOOL resumePlay = NO;
if (self.state == TFBasicVoicePlayerStatePlaying || self.state == TFBasicVoicePlayerStateLoading) {
self.state = TFBasicVoicePlayerStatePause;
[self.player pause];
resumePlay = YES;
}
[self didSeekToTime:value resumePlay:resumePlay completionBlock:completionBlock];
}
- (void)didSeekToTime:(CGFloat)value resumePlay:(BOOL)resumePlay completionBlock:(void (^)(void))completionBlock
{
[self.player seekToTime:CMTimeMake(floorf(self.totalTime * value), 1)
toleranceBefore:kCMTimeZero
toleranceAfter:kCMTimeZero
completionHandler:^(BOOL finished) {
if (finished) {
self->_isSeek = NO;
[self play];
if (!resumePlay) {
[self pause];
}
if (completionBlock) {
completionBlock();
}
}
}];
}
/**倍速播放*/
- (void)setRate:(CGFloat)rate {
_playRate = rate;
for (AVPlayerItemTrack *track in self.playerItem.tracks){
if ([track.assetTrack.mediaType isEqual:AVMediaTypeAudio]){
track.enabled = YES;
}
}
if (self.state == TFBasicVoicePlayerStatePlaying) {
self.player.rate = rate;
}
}
/**释放播放器*/
- (void)deallocPlayer{
[self reset];
self.state = TFBasicVoicePlayerStateStoped;
if (@available(iOS 7.1, *)) {
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
[[center playCommand] removeTarget:self];
[[center pauseCommand] removeTarget:self];
[[center nextTrackCommand] removeTarget:self];
[[center previousTrackCommand] removeTarget:self];
[[center togglePlayPauseCommand] removeTarget:self];
if(@available(iOS 9.1, *)) {
[center.changePlaybackPositionCommand removeTarget:self];
}
}
if (_isOtherPlaying) {
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}else{
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
[self.player.currentItem cancelPendingSeeks];
[self.player.currentItem.asset cancelLoading];
if (self.playerModelArray) {
self.playerModelArray = nil;
}
if (self.playerItem) {
self.playerItem = nil;
}
if (self.player) {
self.player = nil;
}
}
- (void)reset{
if (self.state == TFBasicVoicePlayerStatePlaying) {
[self.player pause];
}
//移除进度观察者
if (self.timeObserver) {
[self.player removeTimeObserver:self.timeObserver];
self.timeObserver = nil;
}
//重置
self.progress = .0f;
self.bufferProgress = .0f;
self.currentTime = .0f;
self.totalTime = .0f;
}
#pragma mark - 播放 暂停 下一首 上一首
/**播放*/
- (void)play
{
[self.player play];
self.player.rate = self.playRate;
self.state = TFBasicVoicePlayerStateLoading;
if (self.delegate && [self.delegate respondsToSelector:@selector(playerStateChange:)]) {
[self.delegate playerStateChange:self.state];
}
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
});
}
/**暂停*/
- (void)pause
{
[self.player pause];
self.state = TFBasicVoicePlayerStatePause;
if (self.delegate && [self.delegate respondsToSelector:@selector(playerStateChange:)]) {
[self.delegate playerStateChange:self.state];
}
}
/**下一首*/
- (void)next
{
if (self.delegate && [self.delegate respondsToSelector:@selector(audioPlayerRemoteCenterSwitchToNext)]) {
[self.delegate audioPlayerRemoteCenterSwitchToNext];
}
}
/**上一首*/
- (void)last
{
if (self.delegate && [self.delegate respondsToSelector:@selector(audioPlayerRemoteCenterSwitchToPrevious)]) {
[self.delegate audioPlayerRemoteCenterSwitchToPrevious];
}
}
#pragma mark - setter
- (void)setCategory:(AVAudioSessionCategory)category{
[[AVAudioSession sharedInstance] setCategory:category error:nil];
}
- (void)setPlayerItem:(AVPlayerItem *)playerItem{
if (_playerItem == playerItem) {
return;
}
if (_playerItem) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
[_playerItem removeObserver:self forKeyPath:WXYZStatusKey];
[_playerItem removeObserver:self forKeyPath:WXYZLoadedTimeRangesKey];
[_playerItem removeObserver:self forKeyPath:WXYZPlaybackBufferEmptyKey];
[_playerItem removeObserver:self forKeyPath:WXYZPlaybackLikelyToKeepUpKey];
}
_playerItem = playerItem;
if (playerItem) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
[playerItem addObserver:self forKeyPath:WXYZStatusKey options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:WXYZLoadedTimeRangesKey options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:WXYZPlaybackBufferEmptyKey options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:WXYZPlaybackLikelyToKeepUpKey options:NSKeyValueObservingOptionNew context:nil];
}
}
@end

Some files were not shown because too many files have changed in this diff Show More