// // TFBookRackCommViewController.m // WXReader // // Created by 谢腾飞 on 2020/12/1. // Copyright © 2020 xtfei_2011@126.com. All rights reserved. // #import "TFBookRackCommViewController.h" #if TF_Enable_Book #import "TFReadNovelViewController.h" #endif #if TF_Enable_Comic #import "TFComicBrowseViewController.h" #endif #if TF_Enable_Audio #import "TFAudioPlayViewController.h" #endif #import "TFAnnouncementController.h" #import "TFTaskViewController.h" #import "TFBookRackCommCell.h" #import "TFBookRackAddMoreCell.h" #import "TFBookRackHeaderView.h" #import "TFCollectionManager.h" #import "TFReadRecordManager.h" #import "NSObject+Observer.h" @interface TFBookRackCommViewController () @property (nonatomic ,strong) TFBookRackHeaderView *headerView; @property (nonatomic ,strong) UIView *toolBarView; @property (nonatomic ,strong) UIButton *deleteBtn; @property (nonatomic ,strong) UIButton *checkAllBtn; @property (nonatomic ,strong) TFBookRackModel *bookRackModel; @property (nonatomic ,strong) NSMutableArray *deleteSourceArray; // 角标记录 @property (nonatomic ,strong) NSMutableDictionary *badges; @property (nonatomic ,assign) BOOL editingProduction; @end @implementation TFBookRackCommViewController - (void)viewDidLoad { [super viewDidLoad]; [self initialize]; [self createSubviews]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self setStatusBarDefaultStyle]; [self localSourceRequest]; [self netRequest]; } - (void)initialize { [self hiddenNavigationBar:YES]; self.view.backgroundColor = kWhiteColor; self.deleteSourceArray = [NSMutableArray array]; // 签到加入书架 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localSourceRequest) name:Notification_Reload_Rack_Production object:nil]; } - (void)createSubviews { self.mainCollectionViewFlowLayout.minimumLineSpacing = kMargin; self.mainCollectionViewFlowLayout.minimumInteritemSpacing = 0; self.mainCollectionViewFlowLayout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, Rack_Header_Height); self.mainCollectionViewFlowLayout.footerReferenceSize = CGSizeMake(SCREEN_WIDTH, kHalfMargin); self.mainCollectionViewFlowLayout.itemSize = CGSizeMake(BOOK_WIDTH, BOOK_HEIGHT + BOOK_CELL_TITLE_HEIGHT / 2); self.mainCollectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(0, kHalfMargin, 0, kHalfMargin); self.mainCollectionView.delegate = self; self.mainCollectionView.dataSource = self; [self.mainCollectionView registerClass:[TFBookRackCommCell class] forCellWithReuseIdentifier:@"TFBookRackCommCell"]; [self.mainCollectionView registerClass:[TFBookRackAddMoreCell class] forCellWithReuseIdentifier:@"TFBookRackAddMoreCell"]; [self.mainCollectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; [self.mainCollectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView"]; [self.view addSubview:self.mainCollectionView]; [self.mainCollectionView 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); }]; UILongPressGestureRecognizer *editLongPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(startEdited:)]; editLongPressGesture.minimumPressDuration = 1.0f; editLongPressGesture.numberOfTouchesRequired = 1; [self.mainCollectionView addGestureRecognizer:editLongPressGesture]; WS(weakSelf) self.mainCollectionView.mj_header = [TFRefreshHeader headerWithRefreshingBlock:^{ [weakSelf localSourceRequest]; [weakSelf netRequest]; }]; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { if (self.editingProduction) { return self.dataSourceArray.count; } return self.dataSourceArray.count + 1; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { if (self.dataSourceArray.count == indexPath.row && !self.editingProduction) { static NSString *CellIdentifier = @"TFBookRackAddMoreCell"; TFBookRackAddMoreCell __weak *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; return cell; } else { static NSString *CellIdentifier = @"TFBookRackCommCell"; TFBookRackCommCell __weak *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; TFProductionModel *t_bookModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row]; cell.productionModel = t_bookModel; cell.badgeNum = [TFUtilsHelper formatStringWithInteger:[[self.badges objectForKey:[TFUtilsHelper formatStringWithInteger:t_bookModel.production_id]] total_chapters]]; cell.bookSeleced = NO; cell.startEditing = self.editingProduction; for (TFProductionModel *t_model in self.deleteSourceArray) { if (t_model.production_id == t_bookModel.production_id) { cell.bookSeleced = YES; } } return cell; } } - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { UICollectionReusableView *headerReusableView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; headerReusableView.backgroundColor = [UIColor clearColor]; if (self.bookRackModel && self.bookRackModel.recommendList.count > 0 && !self.editingProduction) { self.headerView.rackModel = self.bookRackModel; [self showHeaderViewWithAnimated:NO]; } else if (self.bookRackModel) { [self hiddenHeaderViewWithAnimated:NO]; } [headerReusableView addSubview:self.headerView]; return headerReusableView; } else { UICollectionReusableView *footerReusableView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath]; return footerReusableView; } } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (self.dataSourceArray.count == indexPath.row && !self.editingProduction) { [[NSNotificationCenter defaultCenter] postNotificationName:Notification_Change_Tabbar_Index object:@"1"]; switch (self.productionType) { #if TF_Enable_Book case TFProductionTypeNovel: [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Rack_JumpToMallCenter object:@"novel"]; break; #endif #if TF_Enable_Comic case TFProductionTypeComic: [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Rack_JumpToMallCenter object:@"comic"]; break; #endif #if TF_Enable_Audio case TFProductionTypeAudio: [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification_Rack_JumpToMallCenter object:@"audio"]; break; #endif default: break; } } else { TFBookRackCommCell *cell = (TFBookRackCommCell *)[collectionView cellForItemAtIndexPath:indexPath]; TFProductionModel *productionModel = [self.dataSourceArray objectOrNilAtIndex:indexPath.row]; if (!self.editingProduction) { [[TFCollectionManager shareManagerWithProductionType:self.productionType] moveCollectionToTopWithProductionModel:productionModel]; switch (self.productionType) { #if TF_Enable_Book case TFProductionTypeNovel: { if (self.pushToReaderViewControllerBlock) { self.pushToReaderViewControllerBlock(cell.coverView, productionModel); } } break; #endif #if TF_Enable_Comic case TFProductionTypeComic: { TFComicBrowseViewController *comicBrowse = [[TFComicBrowseViewController alloc] init]; comicBrowse.comicProductionModel = productionModel; comicBrowse.chapter_id = [[TFReadRecordManager shareManagerWithProductionType:TFProductionTypeComic] getReadingRecordChapter_idWithProduction_id:productionModel.production_id]; [self.navigationController pushViewController:comicBrowse animated:YES]; } break; #endif #if TF_Enable_Audio case TFProductionTypeAudio: { TFAudioPlayViewController *audioPlay = [[TFAudioPlayViewController alloc] init]; [audioPlay loadDataWithAudio_id:productionModel.production_id chapter_id:0]; TFNavigationController *nav = [[TFNavigationController alloc] initWithRootViewController:audioPlay]; [[TFViewHelper getWindowRootController] presentViewController:nav animated:YES completion:nil]; } break; #endif default: break; } // 读书任务请求 [TFTaskViewController taskReadRequestWithProduction_id:productionModel.production_id]; // 如果有更新则更新本地数据源 if ([cell.badgeNum integerValue] > 0) { TFProductionModel *t_model = [self.badges objectForKey:[TFUtilsHelper formatStringWithInteger:productionModel.production_id]]; if (t_model) { [[TFCollectionManager shareManagerWithProductionType:self.productionType] modificationCollectionWithProductionModel:t_model]; } } return; } if (cell.bookSeleced) { cell.bookSeleced = NO; [self.deleteSourceArray removeObject:productionModel]; } else { cell.bookSeleced = YES; [self.deleteSourceArray addObject:productionModel]; } [self reloadToolBarState]; } } #pragma mark - 点击事件 - (void)showHeaderViewWithAnimated:(BOOL)animated { if (self.bookRackModel.recommendList.count == 0) return; [self.mainCollectionView showRefreshHeader]; [UIView animateWithDuration:animated?kAnimatedDuration:0.0f animations:^{ if (self.bookRackModel.announcement.count > 0) { self.headerView.frame = CGRectMake(0, 0, SCREEN_WIDTH, Rack_Header_Height); self.mainCollectionViewFlowLayout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, Rack_Header_Height); } else { self.headerView.frame = CGRectMake(0, 0, SCREEN_WIDTH, Rack_Header_Height_NoRecommend); self.mainCollectionViewFlowLayout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, Rack_Header_Height_NoRecommend); } [self.mainCollectionView setCollectionViewLayout:self.mainCollectionViewFlowLayout animated:animated]; }]; } - (void)hiddenHeaderViewWithAnimated:(BOOL)animated { [self.mainCollectionView hideRefreshHeader]; [UIView animateWithDuration:animated?kAnimatedDuration:0.0f animations:^{ self.headerView.frame = CGRectMake(0, 0, SCREEN_WIDTH, 0); self.mainCollectionViewFlowLayout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, 10); [self.mainCollectionView setCollectionViewLayout:self.mainCollectionViewFlowLayout animated:animated]; }]; } // 工具栏点击 - (void)toolBarActionClick:(UIButton *)sender { switch (sender.tag) { case 11: // 取消操作 [self endEdited]; break; case 22: { // 删除操作 if (self.deleteSourceArray.count == 0) { return; } NSMutableArray *t_deleteArray = [NSMutableArray array]; for (TFProductionModel *t_model in self.deleteSourceArray) { [[TFCollectionManager shareManagerWithProductionType:self.productionType] removeCollectionWithProductionModel:t_model]; [t_deleteArray addObject:[TFUtilsHelper formatStringWithInteger:t_model.production_id]]; } NSString *url = @""; NSString *production_key = @""; switch (self.productionType) { case TFProductionTypeNovel: url = Book_Delete_Collect; production_key = @"book_id"; break; case TFProductionTypeComic: url = Comic_Collect_Delete; production_key = @"comic_id"; break; case TFProductionTypeAudio: url = Audio_Collection_Delete; production_key = @"audio_id"; break; default: break; } [TFNetworkTools POST:url parameters:@{production_key:[t_deleteArray componentsJoinedByString:@","]} model:nil success:nil failure:nil]; [self endEdited]; [self localSourceRequest]; } case 33: { // 全选/取消操作 [self.deleteSourceArray removeAllObjects]; if (!sender.selected) { self.deleteSourceArray = [self.dataSourceArray mutableCopy]; [sender setTitle:TFLocalizedString(@"取消全选") forState:UIControlStateNormal]; } else { [sender setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal]; [self.deleteSourceArray removeAllObjects]; } sender.selected = !sender.selected; [self.mainCollectionView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj isKindOfClass:[TFBookRackCommCell class]]) { TFBookRackCommCell *cell = (TFBookRackCommCell *)obj; cell.bookSeleced = sender.selected; } }]; [self reloadToolBarState]; } break; default: break; } } // 开启编辑状态 - (void)startEdited:(UILongPressGestureRecognizer *)gestureRecognizer { if (gestureRecognizer.state != UIGestureRecognizerStateBegan) { return; } if (self.editingProduction) { return; } self.editingProduction = YES; [self.deleteSourceArray removeAllObjects]; CGPoint pointTouch = [gestureRecognizer locationInView:self.mainCollectionView]; if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { NSIndexPath *indexPath = [self.mainCollectionView indexPathForItemAtPoint:pointTouch]; if ([[self.mainCollectionView cellForItemAtIndexPath:indexPath] isKindOfClass:[TFBookRackCommCell class]]) { // 获取当前被点击的书籍,默认选中 TFBookRackCommCell *t_cell = (TFBookRackCommCell *)[self.mainCollectionView cellForItemAtIndexPath:indexPath]; [self.deleteSourceArray addObject:t_cell.productionModel]; // 隐藏推荐栏 [self hiddenHeaderViewWithAnimated:YES]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((kAnimatedDuration + 0.1) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.mainCollectionView reloadData]; }); [UIView animateWithDuration:kAnimatedDuration animations:^{ self.toolBarView.frame = CGRectMake(0, SCREEN_HEIGHT - PUB_TABBAR_HEIGHT, SCREEN_WIDTH, PUB_TABBAR_HEIGHT); }]; [self reloadToolBarState]; } else { self.editingProduction = NO; } } } - (void)endEdited { self.editingProduction = NO; [self showHeaderViewWithAnimated:YES]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kAnimatedDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.mainCollectionView reloadData]; }); [UIView animateWithDuration:kAnimatedDuration animations:^{ self.toolBarView.frame = CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, PUB_TABBAR_HEIGHT); }]; [self reloadToolBarState]; } - (void)reloadToolBarState { if (self.deleteSourceArray.count == 0) { self.deleteBtn.backgroundColor = kGrayLineColor; self.deleteBtn.enabled = NO; [self.deleteBtn setTitle:TFLocalizedString(@"删除(0)") forState:UIControlStateNormal]; [self.deleteBtn setTitleColor:kGrayTextColor forState:UIControlStateNormal]; self.checkAllBtn.selected = NO; [self.checkAllBtn setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal]; } else { self.deleteBtn.backgroundColor = kRedColor; self.deleteBtn.enabled = YES; [self.deleteBtn setTitle:[NSString stringWithFormat:@"%@(%@)", TFLocalizedString(@"删除"), [TFUtilsHelper formatStringWithInteger:self.deleteSourceArray.count]] forState:UIControlStateNormal]; [self.deleteBtn setTitleColor:kWhiteColor forState:UIControlStateNormal]; if (self.deleteSourceArray.count == self.dataSourceArray.count) { self.checkAllBtn.selected = YES; [self.checkAllBtn setTitle:TFLocalizedString(@"取消全选") forState:UIControlStateNormal]; } else { self.checkAllBtn.selected = NO; [self.checkAllBtn setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal]; } } } - (TFBookRackHeaderView *)headerView { if (!_headerView) { WS(weakSelf) _headerView = [[TFBookRackHeaderView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, Rack_Header_Height)]; _headerView.backgroundColor = [UIColor whiteColor]; _headerView.productionType = self.productionType; _headerView.adBannerClickBlock = ^(NSString * _Nonnull title, NSString * _Nonnull content) { TFAnnouncementController *vc = [[TFAnnouncementController alloc] init]; vc.titleText = title?:@""; vc.contentText = content?:@""; [weakSelf.navigationController pushViewController:vc animated:YES]; }; _headerView.recommendBannerClickBlock = ^(NSInteger production_id) { switch (weakSelf.productionType) { #if TF_Enable_Book case TFProductionTypeNovel: { TFNovelDetailViewController *novelDetail = [[TFNovelDetailViewController alloc] init]; novelDetail.book_id = production_id; [weakSelf.navigationController pushViewController:novelDetail animated:YES]; } break; #endif #if TF_Enable_Comic case TFProductionTypeComic: { TFComicDetailViewController *comicDetail = [[TFComicDetailViewController alloc] init]; comicDetail.comic_id = production_id; [weakSelf.navigationController pushViewController:comicDetail animated:YES]; } break; #endif #if TF_Enable_Audio case TFProductionTypeAudio: { TFAudioDetailViewController *audioDetail = [[TFAudioDetailViewController alloc] init]; audioDetail.audio_id = production_id; [weakSelf.navigationController pushViewController:audioDetail animated:YES]; } break; #endif default: break; } }; _headerView.collectionClickBlock = ^{ [weakSelf.navigationController pushViewController:[[TFTaskViewController alloc] init] animated:YES]; }; } return _headerView; } - (UIView *)toolBarView { if (!_toolBarView) { _toolBarView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, PUB_TABBAR_HEIGHT)]; _toolBarView.backgroundColor = kWhiteColor; WS(weakSelf) [_toolBarView addObserver:KEY_PATH(_toolBarView, frame) complete:^(UIView * _Nonnull toolBarView, id _Nullable oldVal, id _Nullable newVal) { CGRect frame = [newVal CGRectValue]; if (CGRectGetMinY(frame) >= SCREEN_HEIGHT) { toolBarView.hidden = YES; weakSelf.tabBarController.tabBar.hidden = NO; } else { toolBarView.hidden = NO; weakSelf.tabBarController.tabBar.hidden = YES; } }]; [self.view addSubview:_toolBarView]; UIButton *checkAllBtn = [UIButton buttonWithType:UIButtonTypeCustom]; checkAllBtn.tag = 33; checkAllBtn.selected = NO; checkAllBtn.frame = CGRectMake(0, 0, SCREEN_WIDTH / 3, PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET); checkAllBtn.adjustsImageWhenHighlighted = NO; [checkAllBtn setTitle:TFLocalizedString(@"全选") forState:UIControlStateNormal]; [checkAllBtn setTitleColor:kBlackColor forState:UIControlStateNormal]; [checkAllBtn.titleLabel setFont:kMainFont]; [checkAllBtn addTarget:self action:@selector(toolBarActionClick:) forControlEvents:UIControlEventTouchUpInside]; [_toolBarView addSubview:checkAllBtn]; self.checkAllBtn = checkAllBtn; UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom]; deleteBtn.frame = CGRectMake(SCREEN_WIDTH / 3, 0, SCREEN_WIDTH / 3, PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET); deleteBtn.backgroundColor = kGrayLineColor; deleteBtn.tag = 22; [deleteBtn setTitleColor:kGrayTextColor forState:UIControlStateNormal]; [deleteBtn setTitle:TFLocalizedString(@"删除") forState:UIControlStateNormal]; [deleteBtn.titleLabel setFont:kMainFont]; [deleteBtn addTarget:self action:@selector(toolBarActionClick:) forControlEvents:UIControlEventTouchUpInside]; [_toolBarView addSubview:deleteBtn]; self.deleteBtn = deleteBtn; UIButton *cancleButton = [UIButton buttonWithType:UIButtonTypeCustom]; cancleButton.frame = CGRectMake(SCREEN_WIDTH / 3 * 2, 0, SCREEN_WIDTH / 3, PUB_TABBAR_HEIGHT - PUB_TABBAR_OFFSET); cancleButton.tag = 11; [cancleButton setTitle:TFLocalizedString(@"取消") forState:UIControlStateNormal]; [cancleButton setTitleColor:kBlackColor forState:UIControlStateNormal]; [cancleButton.titleLabel setFont:kMainFont]; [cancleButton addTarget:self action:@selector(toolBarActionClick:) forControlEvents:UIControlEventTouchUpInside]; [_toolBarView addSubview:cancleButton]; } return _toolBarView; } // 加载本地书籍缓存 - (void)localSourceRequest { NSArray *cacheArray = [[TFCollectionManager shareManagerWithProductionType:self.productionType] getAllCollection]; if (![cacheArray isEqualToArray:self.dataSourceArray]) { self.dataSourceArray = [cacheArray mutableCopy]; [self.mainCollectionView reloadData]; } [self.mainCollectionView scrollToTop]; [self.mainCollectionView endRefreshing]; } - (void)netRequest { // 书籍更新角标 self.badges = [NSMutableDictionary dictionary]; NSString *url = @""; switch (self.productionType) { case TFProductionTypeNovel: url = Book_Rack; break; case TFProductionTypeComic: url = Comic_Rack; break; case TFProductionTypeAudio: url = Audio_Rack; break; default: break; } WS(weakSelf) [TFNetworkTools POST:url parameters:nil model:TFBookRackModel.class success:^(BOOL isSuccess, TFBookRackModel * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) { if (isSuccess) { weakSelf.bookRackModel = t_model; for (TFProductionModel *t_model in weakSelf.bookRackModel.productionList) { [weakSelf.badges setObject:t_model forKey:[TFUtilsHelper formatStringWithInteger:t_model.production_id]]; } } [weakSelf.mainCollectionView endRefreshing]; [weakSelf.mainCollectionView reloadData]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { [weakSelf.mainCollectionView endRefreshing]; [weakSelf.mainCollectionView reloadData]; }]; } @end