diff --git a/BeeReel.xcodeproj/project.pbxproj b/BeeReel.xcodeproj/project.pbxproj index 386c3b1..dde285c 100644 --- a/BeeReel.xcodeproj/project.pbxproj +++ b/BeeReel.xcodeproj/project.pbxproj @@ -59,6 +59,8 @@ BF3A56812E30C08F009E5CF9 /* BRHotSearchTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3A56802E30C08F009E5CF9 /* BRHotSearchTagCell.swift */; }; BF3A56832E30C561009E5CF9 /* BRSearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3A56822E30C561009E5CF9 /* BRSearchResultView.swift */; }; BF3A56852E30CA78009E5CF9 /* BRSearchResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3A56842E30CA78009E5CF9 /* BRSearchResultCell.swift */; }; + BF3A56882E30E0DD009E5CF9 /* BREmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3A56872E30E0DD009E5CF9 /* BREmpty.swift */; }; + BF3A568A2E30E7EF009E5CF9 /* BRNetworkStatusManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3A56892E30E7EF009E5CF9 /* BRNetworkStatusManager.swift */; }; BF692AEB2E0A475D00A5C2DA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF692AE12E0A475D00A5C2DA /* AppDelegate.swift */; }; BF692AEC2E0A475D00A5C2DA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF692AE82E0A475D00A5C2DA /* SceneDelegate.swift */; }; BF692AEE2E0A475D00A5C2DA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF692AE22E0A475D00A5C2DA /* Assets.xcassets */; }; @@ -204,6 +206,8 @@ BF3A56802E30C08F009E5CF9 /* BRHotSearchTagCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHotSearchTagCell.swift; sourceTree = ""; }; BF3A56822E30C561009E5CF9 /* BRSearchResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRSearchResultView.swift; sourceTree = ""; }; BF3A56842E30CA78009E5CF9 /* BRSearchResultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRSearchResultCell.swift; sourceTree = ""; }; + BF3A56872E30E0DD009E5CF9 /* BREmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BREmpty.swift; sourceTree = ""; }; + BF3A56892E30E7EF009E5CF9 /* BRNetworkStatusManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRNetworkStatusManager.swift; sourceTree = ""; }; BF692AC92E0A475500A5C2DA /* BeeReel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BeeReel.app; sourceTree = BUILT_PRODUCTS_DIR; }; BF692AE12E0A475D00A5C2DA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; BF692AE22E0A475D00A5C2DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -491,6 +495,14 @@ path = View; sourceTree = ""; }; + BF3A56862E30E0C2009E5CF9 /* Empty */ = { + isa = PBXGroup; + children = ( + BF3A56872E30E0DD009E5CF9 /* BREmpty.swift */, + ); + path = Empty; + sourceTree = ""; + }; BF692AC02E0A475500A5C2DA = { isa = PBXGroup; children = ( @@ -574,6 +586,7 @@ BF692AF62E0A480000A5C2DA /* Lib */ = { isa = PBXGroup; children = ( + BF3A56862E30E0C2009E5CF9 /* Empty */, BF692B452E0A9B5800A5C2DA /* Player */, BF692B1D2E0A803000A5C2DA /* LocalizedManager */, BF692B142E0A7CB500A5C2DA /* HUD */, @@ -846,6 +859,7 @@ BF692AFB2E0A6F1B00A5C2DA /* BRNetworkTarget.swift */, BF692AF92E0A6EFD00A5C2DA /* BRNetwork.swift */, BF78108A2E0D4EB3007DEEBC /* BRURLPath.swift */, + BF3A56892E30E7EF009E5CF9 /* BRNetworkStatusManager.swift */, ); path = Base; sourceTree = ""; @@ -1090,6 +1104,7 @@ BFC676932E126A62006659E5 /* BRSpotlightNewMainCell.swift in Sources */, BFC6768D2E123D6E006659E5 /* AttributedString+BRAdd.swift in Sources */, BF02B8392E30B30400172177 /* AlignedCollectionViewFlowLayout.swift in Sources */, + BF3A56882E30E0DD009E5CF9 /* BREmpty.swift in Sources */, BF3338F52E1616B200B10F76 /* BRExploreControlView.swift in Sources */, BF692B132E0A7B9000A5C2DA /* BRUserInfo.swift in Sources */, BF692B042E0A76D200A5C2DA /* BRLoginManager.swift in Sources */, @@ -1145,6 +1160,7 @@ BF02B7F52E2F203D00172177 /* BRHomeCategoriesViewController.swift in Sources */, BFC676752E0E93B3006659E5 /* BRTableViewCell.swift in Sources */, BF78108B2E0D4EB3007DEEBC /* BRURLPath.swift in Sources */, + BF3A568A2E30E7EF009E5CF9 /* BRNetworkStatusManager.swift in Sources */, BF692B092E0A775500A5C2DA /* BRLoginToken.swift in Sources */, BF692AFC2E0A6F8000A5C2DA /* BRNetworkTarget.swift in Sources */, BF02B7FF2E2F2F2900172177 /* BRHomeCategoriesCell.swift in Sources */, diff --git a/BeeReel/Base/Network/Base/BRNetworkStatusManager.swift b/BeeReel/Base/Network/Base/BRNetworkStatusManager.swift new file mode 100644 index 0000000..a756b1d --- /dev/null +++ b/BeeReel/Base/Network/Base/BRNetworkStatusManager.swift @@ -0,0 +1,73 @@ +// +// BRNetworkStatusManager.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/23. +// + +import UIKit +import Network + +class BRNetworkStatusManager: NSObject { + static let manager = BRNetworkStatusManager() + + ///是否有网 + var isReachable: Bool? + + private var connectionType: NWInterface.InterfaceType? + private var status: NWPath.Status? + + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "NetworkMonitorQueue") + + func startMonitoring() { + + monitor.pathUpdateHandler = { [weak self] path in + guard let self = self else { return } + self.status = path.status + + if path.usesInterfaceType(.wifi) { + self.connectionType = .wifi + } else if path.usesInterfaceType(.cellular) { + self.connectionType = .cellular + } else if path.usesInterfaceType(.wiredEthernet) { + self.connectionType = .wiredEthernet + } else { + self.connectionType = nil + } + + + if path.status == .satisfied, self.connectionType != nil { + if self.isReachable == false { + self.isReachable = true + DispatchQueue.main.async { + NotificationCenter.default.post(name: BRNetworkStatusManager.networkStatusDidChangeNotification, object: nil) + } + } else { + self.isReachable = true + } + } else { + if self.isReachable == true { + self.isReachable = false + DispatchQueue.main.async { + NotificationCenter.default.post(name: BRNetworkStatusManager.networkStatusDidChangeNotification, object: nil) + } + } else { + self.isReachable = false + } + } + } + + + monitor.start(queue: queue) + } + + func stopMonitoring() { + monitor.cancel() + } +} + +extension BRNetworkStatusManager { + ///网络发生变化 + @objc static let networkStatusDidChangeNotification = NSNotification.Name(rawValue: "BRNetworkStatusManager.networkStatusDidChangeNotification") +} diff --git a/BeeReel/Class/Explore/Controller/BRExploreViewController.swift b/BeeReel/Class/Explore/Controller/BRExploreViewController.swift index e73debf..75d514c 100644 --- a/BeeReel/Class/Explore/Controller/BRExploreViewController.swift +++ b/BeeReel/Class/Explore/Controller/BRExploreViewController.swift @@ -198,6 +198,10 @@ extension BRExploreViewController: BRPlayerListViewControllerDelegate, BRPlayerL videoNameLabel.text = self.viewModel.currentPlayer?.shortModel?.name favoriteButton.isSelected = self.viewModel.currentPlayer?.shortModel?.is_collect ?? true } + + func br_playerViewControllerLoadMoreData(playerViewController: BRPlayerListViewController) { + self.requestDataArr(page: self.page + 1) + } } diff --git a/BeeReel/Class/Favorites/Controller/BRFavoritesViewController.swift b/BeeReel/Class/Favorites/Controller/BRFavoritesViewController.swift index bd4c048..a2904fe 100644 --- a/BeeReel/Class/Favorites/Controller/BRFavoritesViewController.swift +++ b/BeeReel/Class/Favorites/Controller/BRFavoritesViewController.swift @@ -47,6 +47,8 @@ class BRFavoritesViewController: BRViewController { let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.delegate = self collectionView.dataSource = self + collectionView.ly_emptyView = BREmpty.br_normalEmptyView() + collectionView.ly_emptyView.autoShowEmptyView = false collectionView.br_addRefreshHeader { [weak self] in self?.handleHeaderRefresh(nil) } @@ -105,6 +107,13 @@ class BRFavoritesViewController: BRViewController { } } + private func updateEmptyStatus() { + if listArr.isEmpty, self.playHistoryModel == nil { + self.collectionView.ly_showEmpty() + } else { + self.collectionView.ly_hideEmpty() + } + } } @@ -192,6 +201,7 @@ extension BRFavoritesViewController { self.page = page self.collectionView.reloadData() } + self.updateEmptyStatus() completer?() } @@ -202,6 +212,7 @@ extension BRFavoritesViewController { guard let self = self else { return } guard let list = listModel?.list else { return } self.playHistoryModel = list.first + self.updateEmptyStatus() } } diff --git a/BeeReel/Class/Home/Controller/BRHomeViewController.swift b/BeeReel/Class/Home/Controller/BRHomeViewController.swift index 82478df..3209676 100644 --- a/BeeReel/Class/Home/Controller/BRHomeViewController.swift +++ b/BeeReel/Class/Home/Controller/BRHomeViewController.swift @@ -142,6 +142,7 @@ class BRHomeViewController: BRViewController { self.edgesForExtendedLayout = [.top, .bottom] self.statusBarStyle = .lightContent self.navigationController?.isNavigationBarHidden = true + NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: BRNetworkStatusManager.networkStatusDidChangeNotification, object: nil) br_setupUI() @@ -239,6 +240,18 @@ extension BRHomeViewController { } extension BRHomeViewController { + ///网络状态监听 + @objc private func networkStatusDidChangeNotification() { + guard BRNetworkStatusManager.manager.isReachable == true else { + return + } + + if self.viewModel.homeOldDataArr.isEmpty { + self.handleHeaderRefresh(nil) + } + + } + @objc private func handleSearchButton() { let vc = BRSearchViewController() diff --git a/BeeReel/Class/Player/Controller/BRPlayerListViewController.swift b/BeeReel/Class/Player/Controller/BRPlayerListViewController.swift index ddb9887..971c2e2 100644 --- a/BeeReel/Class/Player/Controller/BRPlayerListViewController.swift +++ b/BeeReel/Class/Player/Controller/BRPlayerListViewController.swift @@ -11,15 +11,11 @@ import SJMediaCacheServer @objc protocol BRPlayerListViewControllerDelegate { - ///加载新数据 - @objc optional func br_playerViewControllerLoadNewDataV2(playerViewController: BRPlayerListViewController) ///将要加载更多数据 @objc optional func br_playerViewControllerShouldLoadMoreData(playerViewController: BRPlayerListViewController) -> Bool ///加载更多数据 @objc optional func br_playerViewControllerLoadMoreData(playerViewController: BRPlayerListViewController) - ///向上加载更多数据 - @objc optional func br_playerViewControllerLoadUpMoreData(playerViewController: BRPlayerListViewController) ///当前展示的发生变化 @objc optional func br_playerListViewController(_ viewController: BRPlayerListViewController, didChangeIndexPathForVisible indexPath: IndexPath) @@ -136,9 +132,9 @@ class BRPlayerListViewController: BRViewController { self.viewModel.isPlaying = true -// if getDataCount() - viewModel.currentIndexPath.row <= 2 { -// self.loadMoreData() -// } + if (self.collectionView.contentSize.height - self.collectionView.contentOffset.y) / self.contentSize.height <= 3 { + self.loadMoreData() + } } func pause() { @@ -364,10 +360,6 @@ extension BRPlayerListViewController { } } - private func loadUpMoreData() { - self.delegate?.br_playerViewControllerLoadUpMoreData?(playerViewController: self) - } - private func didChangeIndexPathForVisible() { self.delegate?.br_playerListViewController?(self, didChangeIndexPathForVisible: viewModel.currentIndexPath) } diff --git a/BeeReel/Class/Search/View/BRSearchResultView.swift b/BeeReel/Class/Search/View/BRSearchResultView.swift index b9094a5..b7eed9e 100644 --- a/BeeReel/Class/Search/View/BRSearchResultView.swift +++ b/BeeReel/Class/Search/View/BRSearchResultView.swift @@ -6,6 +6,7 @@ // import UIKit +import LYEmptyView class BRSearchResultView: UIView { @@ -35,6 +36,7 @@ class BRSearchResultView: UIView { collectionView.dataSource = self collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 0) collectionView.register(BRSearchResultCell.self, forCellWithReuseIdentifier: "cell") + collectionView.ly_emptyView = BREmpty.br_normalEmptyView(image: UIImage(named: "empty_search_image"), title: "kSearchEmptyTitle".localized, detailStr: "kSearchEmptyDetail".localized) return collectionView }() diff --git a/BeeReel/Delegate/AppDelegate.swift b/BeeReel/Delegate/AppDelegate.swift index 88ea2aa..b02e8fd 100644 --- a/BeeReel/Delegate/AppDelegate.swift +++ b/BeeReel/Delegate/AppDelegate.swift @@ -14,6 +14,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { BRAppTool.appDelegate = self + BRNetworkStatusManager.manager.startMonitoring() + NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: BRNetworkStatusManager.networkStatusDidChangeNotification, object: nil) BRLoginManager.manager.updateUserInfo(completer: nil) @@ -39,3 +41,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } +extension AppDelegate { + @objc private func networkStatusDidChangeNotification() { + if BRNetworkStatusManager.manager.isReachable == true { + BRLoginManager.manager.updateUserInfo(completer: nil) + } + } +} + diff --git a/BeeReel/Lib/Empty/BREmpty.swift b/BeeReel/Lib/Empty/BREmpty.swift new file mode 100644 index 0000000..51c2147 --- /dev/null +++ b/BeeReel/Lib/Empty/BREmpty.swift @@ -0,0 +1,24 @@ +// +// BREmpty.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/23. +// + +import UIKit +import LYEmptyView + +class BREmpty: NSObject { + + static func br_normalEmptyView(image: UIImage? = UIImage(named: "empty_normal_image"), title: String? = "kNormalRmptyTitle".localized, detailStr: String? = "kNormalRmptyDetail".localized) -> LYEmptyView { + let view = LYEmptyView.empty(with: image, titleStr: title, detailStr: detailStr) + view?.titleLabFont = .fontMedium(ofSize: 15) + view?.titleLabTextColor = .color1C1C1C() + view?.detailLabFont = .fontRegular(ofSize: 12) + view?.detailLabTextColor = .color777777() + view?.contentViewOffset = -100 + view?.subViewMargin = 10 + return view! + } + +} diff --git a/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/Contents.json new file mode 100644 index 0000000..9dc1c74 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.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/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@2x.png b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@2x.png new file mode 100644 index 0000000..173c979 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@3x.png b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@3x.png new file mode 100644 index 0000000..c13a019 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/empty_normal_image.imageset/内容为空@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/Contents.json new file mode 100644 index 0000000..2f17ab2 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.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/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@2x.png b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@2x.png new file mode 100644 index 0000000..e0daf6a Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@3x.png b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@3x.png new file mode 100644 index 0000000..93391f6 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/empty_search_image.imageset/搜索无结果@3x.png differ diff --git a/BeeReel/Sources/Localizable.xcstrings b/BeeReel/Sources/Localizable.xcstrings index 3ec5cbd..8ca4d88 100644 --- a/BeeReel/Sources/Localizable.xcstrings +++ b/BeeReel/Sources/Localizable.xcstrings @@ -122,6 +122,50 @@ } } }, + "kNormalRmptyDetail" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Start exploring and add something" + } + } + } + }, + "kNormalRmptyTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing Here Yet" + } + } + } + }, + "kSearchEmptyDetail" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Check spelling or use simpler keywords" + } + } + } + }, + "kSearchEmptyTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Results Found" + } + } + } + }, "Last Searched" : { "extractionState" : "manual", "localizations" : { diff --git a/Podfile b/Podfile index 5308ba5..da019dc 100644 --- a/Podfile +++ b/Podfile @@ -30,5 +30,6 @@ target 'BeeReel' do pod 'MJRefresh' #刷新控件 pod 'HWPanModal' #底部弹出控制器 pod 'FDFullscreenPopGesture' #全屏手势返回 + pod 'LYEmptyView' end