diff --git a/Podfile b/Podfile index 6ce4cda..07ca518 100644 --- a/Podfile +++ b/Podfile @@ -31,6 +31,8 @@ target 'ShortPlay' do pod 'KTVHTTPCache' #视频缓存 pod 'HWPanModal' #底部弹出控制器 pod 'Kingfisher' #图片加载 + pod 'EmptyStateKit' #空数据页面 + pod 'ReachabilitySwift' #网络状态监控 target 'ShortPlayTests' do diff --git a/Podfile.lock b/Podfile.lock index 3cac271..6f7b1c6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,7 @@ PODS: - Alamofire (5.10.2) - CocoaAsyncSocket (7.6.5) + - EmptyStateKit (1.1.0) - HWPanModal (0.9.9) - Kingfisher (8.3.1) - KTVHTTPCache (3.0.2): @@ -10,6 +11,7 @@ PODS: - Moya/Core (= 15.0.0) - Moya/Core (15.0.0): - Alamofire (~> 5.0) + - ReachabilitySwift (5.2.4) - SmartCodable (4.3.2) - SnapKit (5.7.1) - Toast (4.1.1) @@ -21,11 +23,13 @@ PODS: - ZFPlayer/Core (4.1.4) DEPENDENCIES: + - EmptyStateKit - HWPanModal - Kingfisher - KTVHTTPCache - MJRefresh - Moya + - ReachabilitySwift - SmartCodable - SnapKit - Toast @@ -36,11 +40,13 @@ SPEC REPOS: trunk: - Alamofire - CocoaAsyncSocket + - EmptyStateKit - HWPanModal - Kingfisher - KTVHTTPCache - MJRefresh - Moya + - ReachabilitySwift - SmartCodable - SnapKit - Toast @@ -50,17 +56,19 @@ SPEC REPOS: SPEC CHECKSUMS: Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + EmptyStateKit: dc41e9ce5c6089f67a49d063bce73ade9f2ba73f HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2 Kingfisher: 3204d23de16b5ea53541c44ca5a8efb55741dec3 KTVHTTPCache: 5711692cdf9a5ecfe829b1e16577deb3ffe3dc86 MJRefresh: ff9e531227924c84ce459338414550a05d2aea78 Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee + ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda SmartCodable: 88fbf3d65207c2376fdbce4b080a3d578cb51be8 SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7 ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13 -PODFILE CHECKSUM: 13500f038833f93358c53b1941ce4a7f311776dd +PODFILE CHECKSUM: 3842e01f3a774298d51e08a9caf0e72ea42cd7bc COCOAPODS: 1.16.2 diff --git a/ShortPlay.xcodeproj/project.pbxproj b/ShortPlay.xcodeproj/project.pbxproj index 97b1e68..9003f93 100644 --- a/ShortPlay.xcodeproj/project.pbxproj +++ b/ShortPlay.xcodeproj/project.pbxproj @@ -448,7 +448,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -485,7 +485,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ShortPlay.xcodeproj/xcshareddata/xcschemes/ShortPlay.xcscheme b/ShortPlay.xcodeproj/xcshareddata/xcschemes/ShortPlay.xcscheme new file mode 100644 index 0000000..770ccaf --- /dev/null +++ b/ShortPlay.xcodeproj/xcshareddata/xcschemes/ShortPlay.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ShortPlay/AppDelegate/AppDelegate+Config.swift b/ShortPlay/AppDelegate/AppDelegate+Config.swift index 25c7553..0b3456c 100644 --- a/ShortPlay/AppDelegate/AppDelegate+Config.swift +++ b/ShortPlay/AppDelegate/AppDelegate+Config.swift @@ -33,7 +33,7 @@ extension AppDelegate { let backgroundImage = UIImage(color: .clear) - let backgroundColor = UIColor.clear + let backgroundColor = UIColor.black let shadowImage = UIImage() let shadowColor = UIColor.clear diff --git a/ShortPlay/AppDelegate/AppDelegate.swift b/ShortPlay/AppDelegate/AppDelegate.swift index fcb5809..15a5fba 100644 --- a/ShortPlay/AppDelegate/AppDelegate.swift +++ b/ShortPlay/AppDelegate/AppDelegate.swift @@ -17,8 +17,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.appConfig() SPLoginManager.manager.requestVisitorLogin(completer: nil) + ///开启网络监控 +// SPNetworkReachabilityManager.manager.startMonitoring() + + NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil) + NetworkObserver.share.startMonitoring() return true @@ -38,6 +43,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } + + @objc private func reachabilityDidChangeNotification() { +// if SPNetworkReachabilityManager.manager.isReachable { +// SPLoginManager.manager.requestVisitorLogin(completer: nil) +// } + } } diff --git a/ShortPlay/Base/Networking/API/SPVideoAPI.swift b/ShortPlay/Base/Networking/API/SPVideoAPI.swift index e429e95..299aacd 100644 --- a/ShortPlay/Base/Networking/API/SPVideoAPI.swift +++ b/ShortPlay/Base/Networking/API/SPVideoAPI.swift @@ -43,7 +43,7 @@ class SPVideoAPI: NSObject { } ///收藏短剧 - static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String, success: (() -> Void)?) { + static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String?, success: (() -> Void)?, failure: (() -> Void)? = nil) { let path: String if isCollect { path = "/collect" @@ -51,12 +51,17 @@ class SPVideoAPI: NSObject { path = "/cancelCollect" } + var parameters: [String : Any] = [ + "short_play_id" : shortPlayId, + ] + + if let videoId = videoId { + parameters["video_id"] = videoId + } + var param = SPNetworkParameters(path: path) param.isLoding = true - param.parameters = [ - "short_play_id" : shortPlayId, - "video_id" : videoId - ] + param.parameters = parameters SPNetwork.request(parameters: param) { (response: SPNetworkResponse) in if response.code == SPNetworkCodeSucceed { @@ -65,6 +70,8 @@ class SPVideoAPI: NSObject { "state" : isCollect, "id" : shortPlayId, ]) + } else { + failure?() } } } @@ -83,6 +90,20 @@ class SPVideoAPI: NSObject { } } + ///历史记录列表 + static func requestPlayHistoryList(page: Int, completer: ((_ listModel: SPListModel?) -> Void)?) { + var param = SPNetworkParameters(path: "/myHistorys") + param.method = .get + param.parameters = [ + "current_page" : page, + "page_size" : 20 + ] + + SPNetwork.request(parameters: param) { (response: SPNetworkResponse>) in + completer?(response.data) + } + } + } extension SPVideoAPI { diff --git a/ShortPlay/Base/Networking/Base/SPNetworkReachabilityManager.swift b/ShortPlay/Base/Networking/Base/SPNetworkReachabilityManager.swift new file mode 100644 index 0000000..a9869b1 --- /dev/null +++ b/ShortPlay/Base/Networking/Base/SPNetworkReachabilityManager.swift @@ -0,0 +1,60 @@ +// +// SPNetworkReachabilityManager.swift +// ShortPlay +// +// Created by Overseas on 2025/4/19. +// + +import UIKit +import Network +import Combine +import Alamofire + +class SPNetworkReachabilityManager { +// enum Status { +// case notReachable +// case reachableViaWiFi +// case reachableViaWWAN +// case ethernet +// } + + static let manager: SPNetworkReachabilityManager = SPNetworkReachabilityManager() + + private let reachabilityManager = NetworkReachabilityManager() + + ///是否有网 +// @objc var isReachable: Bool { +// switch currentReachabilityStatus { +// case .notReachable: +// return false +// case .reachableViaWiFi, .reachableViaWWAN: +// return true +// +// default: +// return false +// } +// } + + func startMonitoring() { + + reachabilityManager?.startListening(onUpdatePerforming: { status in + switch status { + case .notReachable: + print("网络不可用") + case .unknown: + print("网络状态未知") + case .reachable(.cellular): + print("蜂窝网络连接") + case .reachable(.ethernetOrWiFi): + print("WiFi 或有线网络连接") + } + }) + + } + +} + +extension SPNetworkReachabilityManager { + ///网络发生变化 + @objc static let reachabilityDidChangeNotification = NSNotification.Name(rawValue: "reachabilityDidChangeNotification") +} diff --git a/ShortPlay/Class/Home/Controller/SPHomePageController.swift b/ShortPlay/Class/Home/Controller/SPHomePageController.swift index 612aa20..3b0e8d8 100644 --- a/ShortPlay/Class/Home/Controller/SPHomePageController.swift +++ b/ShortPlay/Class/Home/Controller/SPHomePageController.swift @@ -11,6 +11,9 @@ class SPHomePageController: SPViewController { private var topModel: SPHomeTopModel? + ///是否在请求中 + private var isRequesting = false + private lazy var categoryArr: [SPHomeCategoryModel] = { let arr = [ SPHomeCategoryModel(category_name: "Hot Picks".localized, category_id: nil, viewController: SPHomeViewController()), @@ -55,7 +58,8 @@ class SPHomePageController: SPViewController { override func viewDidLoad() { super.viewDidLoad() - + NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil) + sp_setupUI() requestData() @@ -97,6 +101,9 @@ extension SPHomePageController { self.navigationController?.pushViewController(vc, animated: true) } + @objc private func reachabilityDidChangeNotification() { + requestData() + } } @@ -130,9 +137,9 @@ extension SPHomePageController: JYPageControllerDelegate, JYPageControllerDataSo extension SPHomePageController { private func requestData() { - if self.topModel != nil { return } - + if self.topModel != nil || isRequesting { return } + isRequesting = true SPHomeAPI.requestHomeTopData { [weak self] model in guard let self = self else { return } if let model = model { @@ -142,6 +149,7 @@ extension SPHomePageController { } self.pageView.reload() } + self.isRequesting = false } } diff --git a/ShortPlay/Class/Home/Controller/SPHomeViewController.swift b/ShortPlay/Class/Home/Controller/SPHomeViewController.swift index 12c42de..01db166 100644 --- a/ShortPlay/Class/Home/Controller/SPHomeViewController.swift +++ b/ShortPlay/Class/Home/Controller/SPHomeViewController.swift @@ -29,6 +29,8 @@ class SPHomeViewController: SPHomeChildController { override func viewDidLoad() { super.viewDidLoad() + NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil) + // view.backgroundColor = .clear requestModuleData() _setupUI() @@ -53,6 +55,12 @@ extension SPHomeViewController { } } +extension SPHomeViewController { + @objc private func reachabilityDidChangeNotification() { + + } +} + //MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource -------------- extension SPHomeViewController: UICollectionViewDelegate, UICollectionViewDataSource { diff --git a/ShortPlay/Class/Mine/Controller/SPAboutUsViewController.swift b/ShortPlay/Class/Mine/Controller/SPAboutUsViewController.swift new file mode 100644 index 0000000..3b75103 --- /dev/null +++ b/ShortPlay/Class/Mine/Controller/SPAboutUsViewController.swift @@ -0,0 +1,18 @@ +// +// SPAboutUsViewController.swift +// ShortPlay +// +// Created by Overseas on 2025/4/19. +// + +import UIKit + +class SPAboutUsViewController: SPViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + } + + +} diff --git a/ShortPlay/Class/Mine/Controller/SPMineViewController.swift b/ShortPlay/Class/Mine/Controller/SPMineViewController.swift index 8faf1f5..42a8eaf 100644 --- a/ShortPlay/Class/Mine/Controller/SPMineViewController.swift +++ b/ShortPlay/Class/Mine/Controller/SPMineViewController.swift @@ -21,6 +21,11 @@ class SPMineViewController: SPViewController { return arr }() + private lazy var headerView: SPMineHeaderView = { + let view = SPMineHeaderView(frame: CGRect(x: 0, y: 0, width: kSPScreenWidth, height: 200)) + return view + }() + private lazy var tableView: SPTableView = { let tableView = SPTableView(frame: .zero, style: .insetGrouped) tableView.delegate = self @@ -49,6 +54,8 @@ class SPMineViewController: SPViewController { extension SPMineViewController { private func _setupUI() { + tableView.tableHeaderView = self.headerView + view.addSubview(tableView) tableView.snp.makeConstraints { make in @@ -84,6 +91,10 @@ extension SPMineViewController: UITableViewDelegate, UITableViewDataSource { vc.urlStr = SPUserAgreementWebUrl self.navigationController?.pushViewController(vc, animated: true) + case .aboutUs: + let vc = SPAboutUsViewController() + self.navigationController?.pushViewController(vc, animated: true) + default: break } diff --git a/ShortPlay/Class/Mine/View/SPMineHeaderView.swift b/ShortPlay/Class/Mine/View/SPMineHeaderView.swift new file mode 100644 index 0000000..8f83277 --- /dev/null +++ b/ShortPlay/Class/Mine/View/SPMineHeaderView.swift @@ -0,0 +1,14 @@ +// +// SPMineHeaderView.swift +// ShortPlay +// +// Created by Overseas on 2025/4/19. +// + +import UIKit + +class SPMineHeaderView: UIView { + + + +} diff --git a/ShortPlay/Class/MyList/Controller/SPCollectListViewController.swift b/ShortPlay/Class/MyList/Controller/SPCollectListViewController.swift index 930778d..e5c174a 100644 --- a/ShortPlay/Class/MyList/Controller/SPCollectListViewController.swift +++ b/ShortPlay/Class/MyList/Controller/SPCollectListViewController.swift @@ -7,12 +7,14 @@ import UIKit -class SPCollectListViewController: SPViewController { +class SPCollectListViewController: SPMyListChildViewController { private lazy var dataArr: [SPShortModel] = [] private var page: Int? + private lazy var deleteGorup = DispatchGroup() + //MARK: UI属性 private lazy var collectionViewLayout: UICollectionViewFlowLayout = { let itemWidth = floor((kSPScreenWidth - 30 - 9 * 2) / 3) @@ -67,6 +69,47 @@ class SPCollectListViewController: SPViewController { self?.collectionView.sp_endFooterRefreshing() } } + + override var sp_isEditing: Bool { + didSet { + self.collectionView.reloadData() + } + } + + override var isAllSelected: Bool { + var result = true + for model in dataArr { + if model.sp_isSelected != true { + result = false + break + } + } + return result + } + + override var selectedCount: Int { + var result = 0 + dataArr.forEach { + if $0.sp_isSelected ?? false { + result += 1 + } + } + return result + } + + + override func setAllSelectedState(isSelected: Bool) { + dataArr.forEach { + $0.sp_isSelected = isSelected + } + self.collectionView.reloadData() + allSelectedStateDidChange?(isSelected) + self.updateDeleteButtonState() + } + + override func handelDeleteButton() { + requestDelete() + } } extension SPCollectListViewController { @@ -87,16 +130,38 @@ extension SPCollectListViewController: UICollectionViewDelegate, UICollectionVie func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = SPCollectListCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) + cell.sp_isEditing = self.sp_isEditing cell.model = dataArr[indexPath.row] return cell } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return self.dataArr.count + let count = self.dataArr.count + if count == 0 { + let parameters = SPEmptyParameters(image: UIImage(named: "empty_image_01")) + let emptyState = SPEmptyState.normail(parameters: parameters) + self.collectionView.emptyState.format = emptyState.format + self.collectionView.emptyState.show(emptyState) + } else { + self.collectionView.emptyState.hide() + } + + return count } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - + let model = dataArr[indexPath.row] + if sp_isEditing { + model.sp_isSelected = !(model.sp_isSelected ?? false) + self.collectionView.reloadData() + + allSelectedStateDidChange?(isAllSelected) + self.updateDeleteButtonState() + } else { + let vc = SPPlayerDetailViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } } } @@ -117,13 +182,33 @@ extension SPCollectListViewController { self.page = page self.collectionView.reloadData() - + if self.sp_isEditing { + self.allSelectedStateDidChange?(self.isAllSelected) + } } completer?() } - } + private func requestDelete() { + + dataArr.forEach { + if $0.sp_isSelected == true, let shortPlayId = $0.short_play_id { + self.deleteGorup.enter() + SPVideoAPI.requestCollectShort(isCollect: false, shortPlayId: shortPlayId, videoId: nil) { [weak self] in + self?.deleteGorup.leave() + } failure: { [weak self] in + self?.deleteGorup.leave() + } + } + } + + self.deleteGorup.notify(queue: DispatchQueue.main) { [weak self] in + self?.requestDataList(page: 1, completer: nil) + } + } + + } diff --git a/ShortPlay/Class/MyList/Controller/SPMyListChildViewController.swift b/ShortPlay/Class/MyList/Controller/SPMyListChildViewController.swift new file mode 100644 index 0000000..c562535 --- /dev/null +++ b/ShortPlay/Class/MyList/Controller/SPMyListChildViewController.swift @@ -0,0 +1,87 @@ +// +// SPMyListChildViewController.swift +// ShortPlay +// +// Created by Overseas on 2025/4/19. +// + +import UIKit + +class SPMyListChildViewController: SPViewController { + + var sp_isEditing = false { + didSet { + deleteButton.isHidden = !sp_isEditing + if sp_isEditing { + self.view.bringSubviewToFront(deleteButton) + } + } + } + + ///是否被全选 + var isAllSelected: Bool { + return false + } + + ///当前被选中的数量 + var selectedCount: Int { + return 0 + } + + ///全选状态发生变化 + var allSelectedStateDidChange: ((_ isAllSelected: Bool) -> Void)? + + + private(set) lazy var deleteButton: UIButton = { + let button = JXButton(type: .custom) + button.setTitle("0", for: .normal) + button.setTitleColor(.color9D9D9D(), for: .disabled) + button.setTitleColor(.colorF564B6(), for: .normal) + button.setImage(UIImage(named: "delete_icon_01"), for: .disabled) + button.setImage(UIImage(named: "delete_icon_02"), for: .normal) + button.jx_font = .fontRegular(ofSize: 14) + button.jx_setBorderColor(.color9D9D9D(), for: .disabled) + button.jx_setBorderColor(.colorF564B6(), for: .normal) + button.space = 7 + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.layer.borderWidth = 0.7 + button.isHidden = true + button.addTarget(self, action: #selector(handelDeleteButton), for: .touchUpInside) + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + updateDeleteButtonState() + + view.addSubview(deleteButton) + + deleteButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(20) + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-20) + make.height.equalTo(48) + } + } + + + ///设置全选状态 + func setAllSelectedState(isSelected: Bool) { } + + + ///更新删除按钮状态 + func updateDeleteButtonState() { + let count = self.selectedCount + + deleteButton.isEnabled = count > 0 + let text = String(format: "Delet (%@)".localized, "\(selectedCount)") + deleteButton.setTitle(text, for: .normal) + } + + @objc func handelDeleteButton() { + + } + + +} diff --git a/ShortPlay/Class/MyList/Controller/SPMyListViewController.swift b/ShortPlay/Class/MyList/Controller/SPMyListViewController.swift index 2fb20ed..cd1912d 100644 --- a/ShortPlay/Class/MyList/Controller/SPMyListViewController.swift +++ b/ShortPlay/Class/MyList/Controller/SPMyListViewController.swift @@ -12,12 +12,40 @@ class SPMyListViewController: SPViewController { private lazy var titles = ["Follow List".localized, "Play List".localized] - private lazy var viewControllers: [SPViewController] = { + private lazy var viewControllers: [SPMyListChildViewController] = { let vc1 = SPCollectListViewController() + vc1.allSelectedStateDidChange = { [weak self] isAllSelected in + self?.allSelectedButton.isSelected = isAllSelected + } let vc2 = SPPlayHistoryViewController() + vc2.allSelectedStateDidChange = { [weak self] isAllSelected in + self?.allSelectedButton.isSelected = isAllSelected + } + return [vc1, vc2] }() + private lazy var sp_isEditing = false { + didSet { + editButton.isHidden = sp_isEditing + pageView.segmentedView.isHidden = sp_isEditing + + cancelButton.isHidden = !sp_isEditing + allSelectedButton.isHidden = !sp_isEditing + pageView.pageContentScrollView.isScrollEnabled = !sp_isEditing + + let vc = viewControllers[pageView.selectedIndex] + vc.sp_isEditing = sp_isEditing + + if !sp_isEditing { + vc.setAllSelectedState(isSelected: false) + allSelectedButton.isSelected = false + } + + } + } + + //MARK: UI属性 private lazy var pageView: JYPageController = { let pageView = JYPageController() pageView.delegate = self @@ -37,6 +65,39 @@ class SPMyListViewController: SPViewController { return pageView }() + private lazy var editButton: UIButton = { + let button = UIButton(type: .custom) + button.setImage(UIImage(named: "delete_icon_01"), for: .normal) + button.addTarget(self, action: #selector(handleEditButton), for: .touchUpInside) + return button + }() + + private lazy var cancelButton: UIButton = { + let button = UIButton(type: .custom) + button.setTitle("Cancel".localized, for: .normal) + button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal) + button.titleLabel?.font = .fontRegular(ofSize: 15) + button.addTarget(self, action: #selector(handleCancelButton), for: .touchUpInside) + button.isHidden = true + return button + }() + + ///全选按钮 + private lazy var allSelectedButton: UIButton = { + let button = JXButton(type: .custom) + button.setTitle("Select All".localized, for: .normal) + button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal) + button.setImage(UIImage(named: "check_icon_01"), for: .normal) + button.setImage(UIImage(named: "check_icon_01_selected"), for: .selected) + button.setImage(UIImage(named: "check_icon_01_selected"), for: [.selected, .highlighted]) + button.jx_font = .fontRegular(ofSize: 15) + button.titleDirection = .right + button.space = 6 + button.isHidden = true + button.addTarget(self, action: #selector(handleAllSelectedButton), for: .touchUpInside) + return button + }() + override func viewDidLoad() { super.viewDidLoad() @@ -48,19 +109,58 @@ class SPMyListViewController: SPViewController { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(true, animated: true) } - - + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + self.sp_isEditing = false + } + + @objc private func handleEditButton() { + self.sp_isEditing = true + } + + @objc private func handleCancelButton() { + self.sp_isEditing = false + } + + @objc private func handleAllSelectedButton() { + let vc = viewControllers[pageView.selectedIndex] + if self.allSelectedButton.isSelected { + vc.setAllSelectedState(isSelected: false) + } else { + vc.setAllSelectedState(isSelected: true) + } + } } extension SPMyListViewController { private func _setupUI() { addChild(pageView) view.addSubview(pageView.view) + view.addSubview(editButton) + view.addSubview(cancelButton) + view.addSubview(allSelectedButton) pageView.view.snp.makeConstraints { make in make.edges.equalToSuperview() } + + editButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-5) + make.top.equalToSuperview().offset(kSPStatusbarHeight + 10) + make.height.equalTo(35) + make.width.equalTo(40) + } + + cancelButton.snp.makeConstraints { make in + make.top.bottom.equalTo(editButton) + make.right.equalTo(editButton) + } + + allSelectedButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(15) + make.top.bottom.equalTo(editButton) + } } } @@ -88,4 +188,12 @@ extension SPMyListViewController: JYPageControllerDelegate, JYPageControllerData return self.viewControllers[index] } + func pageController(_ pageController: JYPageController, didEnterControllerAt index: Int) { + if index == 0 { + self.editButton.isHidden = false + } else { + self.editButton.isHidden = true + } + } + } diff --git a/ShortPlay/Class/MyList/Controller/SPPlayHistoryViewController.swift b/ShortPlay/Class/MyList/Controller/SPPlayHistoryViewController.swift index 91047f2..a4966b7 100644 --- a/ShortPlay/Class/MyList/Controller/SPPlayHistoryViewController.swift +++ b/ShortPlay/Class/MyList/Controller/SPPlayHistoryViewController.swift @@ -7,11 +7,13 @@ import UIKit -class SPPlayHistoryViewController: SPViewController { +class SPPlayHistoryViewController: SPMyListChildViewController { private lazy var dataArr: [SPShortModel] = [] private var page: Int? + private lazy var deleteGorup = DispatchGroup() + //MARK: UI属性 private lazy var collectionViewLayout: UICollectionViewFlowLayout = { let itemWidth = floor((kSPScreenWidth - 30 - 9 * 2) / 3) @@ -21,7 +23,7 @@ class SPPlayHistoryViewController: SPViewController { layout.itemSize = .init(width: itemWidth, height: itemHeight) layout.minimumLineSpacing = 10 layout.minimumInteritemSpacing = 9 - layout.sectionInset = .init(top: 10, left: 15, bottom: 0, right: 15) + layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15) return layout }() @@ -30,6 +32,13 @@ class SPPlayHistoryViewController: SPViewController { let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.delegate = self collectionView.dataSource = self + collectionView.contentInset = .init(top: 10, left: 0, bottom: 0, right: 0) + collectionView.sp_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in + self?.handleHeaderRefresh(nil) + } + collectionView.sp_addRefreshBackFooter { [weak self] in + self?.handleFooterRefresh(nil) + } SPCollectListCell.registerCell(collectionView: collectionView) return collectionView }() @@ -45,7 +54,61 @@ class SPPlayHistoryViewController: SPViewController { override func setBgImageView() { } - + + override func handleHeaderRefresh(_ completer: (() -> Void)?) { + requestDataList(page: 1) { [weak self] in + self?.collectionView.sp_endHeaderRefreshing() + } + } + + override func handleFooterRefresh(_ completer: (() -> Void)?) { + guard let page = self.page else { return } + + requestDataList(page: page + 1) { [weak self] in + self?.collectionView.sp_endFooterRefreshing() + } + } + + override var sp_isEditing: Bool { + didSet { + self.collectionView.reloadData() + } + } + + override var isAllSelected: Bool { + var result = true + for model in dataArr { + if model.sp_isSelected != true { + result = false + break + } + } + return result + } + + override var selectedCount: Int { + var result = 0 + dataArr.forEach { + if $0.sp_isSelected ?? false { + result += 1 + } + } + return result + } + + + override func setAllSelectedState(isSelected: Bool) { + dataArr.forEach { + $0.sp_isSelected = isSelected + } + self.collectionView.reloadData() + allSelectedStateDidChange?(isSelected) + self.updateDeleteButtonState() + } + + override func handelDeleteButton() { + requestDelete() + } } @@ -68,12 +131,38 @@ extension SPPlayHistoryViewController: UICollectionViewDelegate, UICollectionVie func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = SPCollectListCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) + cell.sp_isEditing = self.sp_isEditing cell.model = dataArr[indexPath.row] return cell } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return self.dataArr.count + let count = self.dataArr.count + if count == 0 { + let parameters = SPEmptyParameters(image: UIImage(named: "empty_image_01")) + let emptyState = SPEmptyState.normail(parameters: parameters) + self.collectionView.emptyState.format = emptyState.format + self.collectionView.emptyState.show(emptyState) + } else { + self.collectionView.emptyState.hide() + } + + return count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = dataArr[indexPath.row] + if sp_isEditing { + model.sp_isSelected = !(model.sp_isSelected ?? false) + self.collectionView.reloadData() + + allSelectedStateDidChange?(isAllSelected) + self.updateDeleteButtonState() + } else { + let vc = SPPlayerDetailViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } } } @@ -82,7 +171,7 @@ extension SPPlayHistoryViewController { private func requestDataList(page: Int, completer: (() -> Void)?) { - SPVideoAPI.requestCollectList(page: page) { [weak self] listModel in + SPVideoAPI.requestPlayHistoryList(page: page) { [weak self] listModel in guard let self = self else { return } if let listModel = listModel, let list = listModel.list { @@ -94,12 +183,31 @@ extension SPPlayHistoryViewController { self.page = page self.collectionView.reloadData() - + if self.sp_isEditing { + self.allSelectedStateDidChange?(self.isAllSelected) + } } completer?() } - } + private func requestDelete() { + + dataArr.forEach { + if $0.sp_isSelected == true, let shortPlayId = $0.short_play_id { + self.deleteGorup.enter() + SPVideoAPI.requestCollectShort(isCollect: false, shortPlayId: shortPlayId, videoId: nil) { [weak self] in + self?.deleteGorup.leave() + } failure: { [weak self] in + self?.deleteGorup.leave() + } + } + } + + self.deleteGorup.notify(queue: DispatchQueue.main) { [weak self] in + self?.requestDataList(page: 1, completer: nil) + } + } + + } - diff --git a/ShortPlay/Class/MyList/View/SPCollectListCell.swift b/ShortPlay/Class/MyList/View/SPCollectListCell.swift index 10e3160..fd52a23 100644 --- a/ShortPlay/Class/MyList/View/SPCollectListCell.swift +++ b/ShortPlay/Class/MyList/View/SPCollectListCell.swift @@ -13,6 +13,14 @@ class SPCollectListCell: SPCollectionViewCell { didSet { coverImageView.sp_setImage(url: model?.image_url) titleLabel.text = model?.name + + selectedButton.isSelected = model?.sp_isSelected ?? false + } + } + + var sp_isEditing: Bool = false { + didSet { + selectedButton.isHidden = !sp_isEditing } } @@ -31,6 +39,15 @@ class SPCollectListCell: SPCollectionViewCell { return label }() + private lazy var selectedButton: UIButton = { + let button = UIButton(type: .custom) + button.isHidden = true + button.isUserInteractionEnabled = false + button.setImage(UIImage(named: "check_icon_01"), for: .normal) + button.setImage(UIImage(named: "check_icon_01_selected"), for: .selected) + return button + }() + override init(frame: CGRect) { super.init(frame: frame) @@ -49,6 +66,7 @@ extension SPCollectListCell { private func _setupUI() { contentView.addSubview(coverImageView) contentView.addSubview(titleLabel) + coverImageView.addSubview(selectedButton) coverImageView.snp.makeConstraints { make in make.left.right.top.equalToSuperview() @@ -61,6 +79,11 @@ extension SPCollectListCell { make.right.lessThanOrEqualToSuperview() } + selectedButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-5) + make.top.equalToSuperview().offset(5) + } + } } diff --git a/ShortPlay/Class/Player/Controller/SPPlayerDetailViewController.swift b/ShortPlay/Class/Player/Controller/SPPlayerDetailViewController.swift index 3c3ac09..4be29aa 100644 --- a/ShortPlay/Class/Player/Controller/SPPlayerDetailViewController.swift +++ b/ShortPlay/Class/Player/Controller/SPPlayerDetailViewController.swift @@ -63,7 +63,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController { override func play() { super.play() - if let _ = self.viewModel.currentPlayer?.model as? SPVideoDetailModel, + if let _ = self.detailModel, let videoInfo = self.viewModel.currentPlayer?.videoInfo { SPVideoAPI.requestRequestVideoPlayHistory(videoId: videoInfo.short_play_video_id ?? "", shortPlayId: videoInfo.short_play_id ?? "") diff --git a/ShortPlay/Class/Player/Model/SPShortModel.swift b/ShortPlay/Class/Player/Model/SPShortModel.swift index 2137277..af93082 100644 --- a/ShortPlay/Class/Player/Model/SPShortModel.swift +++ b/ShortPlay/Class/Player/Model/SPShortModel.swift @@ -30,6 +30,8 @@ class SPShortModel: SPModel, SmartCodable { @IgnoredKey var titleAttributedString: NSAttributedString? + @IgnoredKey + var sp_isSelected: Bool? static func mappingForKey() -> [SmartKeyTransformer]? { diff --git a/ShortPlay/Libs/Empty/SPEmptyState.swift b/ShortPlay/Libs/Empty/SPEmptyState.swift new file mode 100644 index 0000000..3e1e6e1 --- /dev/null +++ b/ShortPlay/Libs/Empty/SPEmptyState.swift @@ -0,0 +1,91 @@ +// +// SPEmptyState.swift +// ShortPlay +// +// Created by Overseas on 2025/4/19. +// + +import UIKit +import EmptyStateKit + +struct SPEmptyParameters { +// var title: String = "暂无内容" +// var titleFont: UIFont = UIFont.text_md +// var titleColor: UIColor = UIColor.system_text_secondary_300 + var image: UIImage? = UIImage(named: "empty_image_01") +// var buttonTitle: String? +} + +enum SPEmptyState { + case normail(parameters: SPEmptyParameters) +} + +extension SPEmptyState: CustomState { + + var image: UIImage? { + switch self { + case .normail(let parameters): + return parameters.image + + + } + } + + var title: String? { + switch self { + case .normail(let parameters): + return nil + + } + } + +// var titleButton: String? { +// switch self { +// case .normail(let parameters): +// return parameters.buttonTitle +// } + +} + +extension SPEmptyState { + var format: EmptyStateFormat { + + var format = EmptyStateFormat() + format.backgroundColor = .clear + format.imageSize = self.image?.size ?? .zero +// format.verticalMargin = -10 +// +// format.buttonWidth = 107 +// format.buttonTopMargin = 10 +// format.buttonColor = .system_fill_primary_100 +// format.buttonAttributes = [ +// .font: UIFont.text_md, +// .foregroundColor: UIColor.system_text_secondary_500 +// ] +// +// switch self { +// case .normail(let p): +// format.titleAttributes = [ +// .font: p.titleFont, +// .foregroundColor: p.titleColor +// ] +// +// +// case .login(let p): +// format.titleAttributes = [ +// .font: p.titleFont, +// .foregroundColor: p.titleColor +// ] +// +// +// } + + + + + return format + } +} + + + diff --git a/ShortPlay/Libs/Reachability/NetworkObserver.swift b/ShortPlay/Libs/Reachability/NetworkObserver.swift new file mode 100644 index 0000000..f109b4c --- /dev/null +++ b/ShortPlay/Libs/Reachability/NetworkObserver.swift @@ -0,0 +1,72 @@ +// +// NetworkObserver.swift +// ShortPlay +// +// Created by Overseas on 2025/4/21. +// + +import UIKit +import Network +import Reachability + + +class NetworkObserver { + static let share = NetworkObserver() + + + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "NetworkMonitorQueue") + + func startMonitoring() { + monitor.pathUpdateHandler = { path in + if path.status == .satisfied { + print("++++++Network is available") + } else { + print("++++++No network connection") + } + + if path.usesInterfaceType(.wifi) { + print("++++++Using Wi-Fi") + } + + if path.usesInterfaceType(.cellular) { + print("++++++Using Cellular") + } + } + + monitor.start(queue: queue) + } + + func stopMonitoring() { + monitor.cancel() + } + + /* + private let reachability = try! Reachability() + + func startMonitoring() { + reachability.whenReachable = { reachability in + if reachability.connection == .wifi { + print("++++++Network reachable via Wi-Fi") + } else if reachability.connection == .cellular { + print("++++++Network reachable via Cellular") + } + } + + reachability.whenUnreachable = { _ in + print("++++++Network not reachable") + } + + do { + try reachability.startNotifier() + } catch { + print("++++++Unable to start notifier") + } + } + + func stopMonitoring() { + reachability.stopNotifier() + } + */ + +} diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/Contents.json b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/Contents.json new file mode 100644 index 0000000..328d961 --- /dev/null +++ b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "组件 67 – 2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "组件 67 – 2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@2x.png b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@2x.png new file mode 100644 index 0000000..669f9bb Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@2x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@3x.png b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@3x.png new file mode 100644 index 0000000..a17639a Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01.imageset/组件 67 – 2@3x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/Contents.json b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/Contents.json new file mode 100644 index 0000000..813db8e --- /dev/null +++ b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "组件 67 – 9@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "组件 67 – 9@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@2x.png b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@2x.png new file mode 100644 index 0000000..76bcc22 Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@2x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@3x.png b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@3x.png new file mode 100644 index 0000000..35b6827 Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/check_icon_01_selected.imageset/组件 67 – 9@3x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/Contents.json b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/Contents.json new file mode 100644 index 0000000..42b0bd4 --- /dev/null +++ b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "delet-选中@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "delet-选中@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@2x.png b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@2x.png new file mode 100644 index 0000000..7c04e41 Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@2x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@3x.png b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@3x.png new file mode 100644 index 0000000..60e3e5c Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_01.imageset/delet-选中@3x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json new file mode 100644 index 0000000..6b57fb5 --- /dev/null +++ b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "delete@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "delete@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@2x.png b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@2x.png new file mode 100644 index 0000000..c7278c6 Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@2x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@3x.png b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@3x.png new file mode 100644 index 0000000..419168f Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/icon/delete_icon_02.imageset/delete@3x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/Contents.json b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/Contents.json new file mode 100644 index 0000000..0caa45e --- /dev/null +++ b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "空空如也@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "空空如也@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@2x.png b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@2x.png new file mode 100644 index 0000000..985fa2e Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@2x.png differ diff --git a/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@3x.png b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@3x.png new file mode 100644 index 0000000..f3d5df1 Binary files /dev/null and b/ShortPlay/Source/Assets.xcassets/image/empty_image_01.imageset/空空如也@3x.png differ diff --git a/ShortPlay/Source/en.lproj/Localizable.strings b/ShortPlay/Source/en.lproj/Localizable.strings index 0a10dde..e260d2f 100644 --- a/ShortPlay/Source/en.lproj/Localizable.strings +++ b/ShortPlay/Source/en.lproj/Localizable.strings @@ -30,6 +30,9 @@ "My list" = "My list"; "Follow List" = "Follow List"; "Play List" = "Play List"; +"Cancel" = "Cancel"; +"Select All" = "Select All"; +"Delet (%@)" = "Delet (%@)"; ///视频详情标题 "kPlayerDetailTitleString" = "Episode %@ / %@"; diff --git a/ShortPlay/Thirdparty/JXButton/JXButton.swift b/ShortPlay/Thirdparty/JXButton/JXButton.swift index e1a8929..246bd18 100644 --- a/ShortPlay/Thirdparty/JXButton/JXButton.swift +++ b/ShortPlay/Thirdparty/JXButton/JXButton.swift @@ -211,6 +211,12 @@ class JXButton: UIButton { updateStatus() } } + + override var isEnabled: Bool { + didSet { + updateStatus() + } + } } diff --git a/ShortPlay/Thirdparty/JYPageController/Classes/JYPageController.swift b/ShortPlay/Thirdparty/JYPageController/Classes/JYPageController.swift index e7130c8..a9ab625 100644 --- a/ShortPlay/Thirdparty/JYPageController/Classes/JYPageController.swift +++ b/ShortPlay/Thirdparty/JYPageController/Classes/JYPageController.swift @@ -343,7 +343,7 @@ open class JYPageController: UIViewController { return segment }() - private lazy var pageContentScrollView : UIScrollView = { + private(set) lazy var pageContentScrollView : UIScrollView = { let scrollView = UIScrollView() // scrollView.backgroundColor = .white scrollView.showsHorizontalScrollIndicator = false