首页开发

This commit is contained in:
zjx 2025-07-01 14:33:05 +08:00
parent 69b2658e2c
commit 1914557261
42 changed files with 1510 additions and 39 deletions

View File

@ -90,6 +90,14 @@
BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */; }; BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */; };
BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */; }; BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */; };
BFC6769D2E129794006659E5 /* BRHomeTop10ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */; }; BFC6769D2E129794006659E5 /* BRHomeTop10ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */; };
BFC676A42E129D60006659E5 /* BRHomeTop10Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */; };
BFC676A72E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */; };
BFC676AB2E1372BD006659E5 /* BRHomeTop3Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */; };
BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */; };
BFC676B72E137DFC006659E5 /* BRPopularPicksCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */; };
BFC676B92E1385FC006659E5 /* BRPopularPicksSmallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */; };
BFC676BC2E138ABB006659E5 /* BRNewReleasesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */; };
BFC676BE2E13A8EB006659E5 /* UIScrollView+BRRefresh.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -189,6 +197,14 @@
BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRSpotlightRecommandCell.swift; sourceTree = "<group>"; }; BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRSpotlightRecommandCell.swift; sourceTree = "<group>"; };
BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPagerViewTransformer.swift; sourceTree = "<group>"; }; BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPagerViewTransformer.swift; sourceTree = "<group>"; };
BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop10ViewController.swift; sourceTree = "<group>"; }; BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop10ViewController.swift; sourceTree = "<group>"; };
BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop10Cell.swift; sourceTree = "<group>"; };
BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterfallMutiSectionFlowLayout.swift; sourceTree = "<group>"; };
BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop3Cell.swift; sourceTree = "<group>"; };
BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksViewController.swift; sourceTree = "<group>"; };
BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksCell.swift; sourceTree = "<group>"; };
BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksSmallCell.swift; sourceTree = "<group>"; };
BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRNewReleasesViewController.swift; sourceTree = "<group>"; };
BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+BRRefresh.swift"; sourceTree = "<group>"; };
C8F11086BA392585E9563BA7 /* Pods-ShortBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShortBox.release.xcconfig"; path = "Target Support Files/Pods-ShortBox/Pods-ShortBox.release.xcconfig"; sourceTree = "<group>"; }; C8F11086BA392585E9563BA7 /* Pods-ShortBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShortBox.release.xcconfig"; path = "Target Support Files/Pods-ShortBox/Pods-ShortBox.release.xcconfig"; sourceTree = "<group>"; };
F06627B1DEE86552C2A87AEC /* Pods-BeeReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.debug.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.debug.xcconfig"; sourceTree = "<group>"; }; F06627B1DEE86552C2A87AEC /* Pods-BeeReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.debug.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.debug.xcconfig"; sourceTree = "<group>"; };
F70FA1F4169364C4C53534CE /* Pods-BeeReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.release.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.release.xcconfig"; sourceTree = "<group>"; }; F70FA1F4169364C4C53534CE /* Pods-BeeReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.release.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.release.xcconfig"; sourceTree = "<group>"; };
@ -308,6 +324,7 @@
BF692AF72E0A480E00A5C2DA /* Thirdparty */ = { BF692AF72E0A480E00A5C2DA /* Thirdparty */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BFC676A62E12AF04006659E5 /* FlowLayout */,
BFC676612E0E2C8E006659E5 /* WMZBanner */, BFC676612E0E2C8E006659E5 /* WMZBanner */,
BF692B292E0A84F700A5C2DA /* JXUUID */, BF692B292E0A84F700A5C2DA /* JXUUID */,
); );
@ -353,6 +370,7 @@
BF692B0C2E0A7A9A00A5C2DA /* Extension */ = { BF692B0C2E0A7A9A00A5C2DA /* Extension */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */,
BFC6768C2E123D67006659E5 /* AttributedString+BRAdd.swift */, BFC6768C2E123D67006659E5 /* AttributedString+BRAdd.swift */,
BFC6767A2E0E9736006659E5 /* UIStackView+BRAdd.swift */, BFC6767A2E0E9736006659E5 /* UIStackView+BRAdd.swift */,
BFC6766E2E0E3B51006659E5 /* UIImageView+BRAdd.swift */, BFC6766E2E0E3B51006659E5 /* UIImageView+BRAdd.swift */,
@ -517,6 +535,8 @@
BF692B6A2E0BC85300A5C2DA /* BRHomeViewController.swift */, BF692B6A2E0BC85300A5C2DA /* BRHomeViewController.swift */,
BFC676702E0E9234006659E5 /* BRSpotlightViewViewController.swift */, BFC676702E0E9234006659E5 /* BRSpotlightViewViewController.swift */,
BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */, BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */,
BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */,
BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */,
); );
path = Controller; path = Controller;
sourceTree = "<group>"; sourceTree = "<group>";
@ -524,6 +544,9 @@
BF692B6C2E0BD4B200A5C2DA /* View */ = { BF692B6C2E0BD4B200A5C2DA /* View */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BFC676BA2E138A9A006659E5 /* NewReleases */,
BFC676AC2E137687006659E5 /* PopularPicks */,
BFC6769E2E129CE5006659E5 /* Top10 */,
BFC676762E0E950A006659E5 /* Spotlight */, BFC676762E0E950A006659E5 /* Spotlight */,
BF692B6D2E0BD4CB00A5C2DA /* BRHomeHeaderView.swift */, BF692B6D2E0BD4CB00A5C2DA /* BRHomeHeaderView.swift */,
BFC6766A2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift */, BFC6766A2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift */,
@ -607,6 +630,39 @@
path = Spotlight; path = Spotlight;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
BFC6769E2E129CE5006659E5 /* Top10 */ = {
isa = PBXGroup;
children = (
BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */,
BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */,
);
path = Top10;
sourceTree = "<group>";
};
BFC676A62E12AF04006659E5 /* FlowLayout */ = {
isa = PBXGroup;
children = (
BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */,
);
path = FlowLayout;
sourceTree = "<group>";
};
BFC676AC2E137687006659E5 /* PopularPicks */ = {
isa = PBXGroup;
children = (
BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */,
BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */,
);
path = PopularPicks;
sourceTree = "<group>";
};
BFC676BA2E138A9A006659E5 /* NewReleases */ = {
isa = PBXGroup;
children = (
);
path = NewReleases;
sourceTree = "<group>";
};
DF948F1E234E75684255568B /* Frameworks */ = { DF948F1E234E75684255568B /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -736,7 +792,9 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */, BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */,
BFC676A42E129D60006659E5 /* BRHomeTop10Cell.swift in Sources */,
BF692B3C2E0A8D0200A5C2DA /* BRNavigationController.swift in Sources */, BF692B3C2E0A8D0200A5C2DA /* BRNavigationController.swift in Sources */,
BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */,
BFC676692E0E34DA006659E5 /* BRUserAPI.swift in Sources */, BFC676692E0E34DA006659E5 /* BRUserAPI.swift in Sources */,
BFC676782E0E9553006659E5 /* BRSpotlightMainBaseCell.swift in Sources */, BFC676782E0E9553006659E5 /* BRSpotlightMainBaseCell.swift in Sources */,
BFC676732E0E938B006659E5 /* BRTableView.swift in Sources */, BFC676732E0E938B006659E5 /* BRTableView.swift in Sources */,
@ -765,10 +823,12 @@
BF692B102E0A7B4300A5C2DA /* BRUserDefaultsKey.swift in Sources */, BF692B102E0A7B4300A5C2DA /* BRUserDefaultsKey.swift in Sources */,
BFC676852E122D9E006659E5 /* BRVideoDetailViewController.swift in Sources */, BFC676852E122D9E006659E5 /* BRVideoDetailViewController.swift in Sources */,
BFC676912E126248006659E5 /* BRSpotlightTopCell.swift in Sources */, BFC676912E126248006659E5 /* BRSpotlightTopCell.swift in Sources */,
BFC676B72E137DFC006659E5 /* BRPopularPicksCell.swift in Sources */,
BF692B422E0A8FB500A5C2DA /* UIFont+BRAdd.swift in Sources */, BF692B422E0A8FB500A5C2DA /* UIFont+BRAdd.swift in Sources */,
BF692AEC2E0A475D00A5C2DA /* SceneDelegate.swift in Sources */, BF692AEC2E0A475D00A5C2DA /* SceneDelegate.swift in Sources */,
BF692B492E0A9D0E00A5C2DA /* UIView+BRAdd.swift in Sources */, BF692B492E0A9D0E00A5C2DA /* UIView+BRAdd.swift in Sources */,
BFC676812E122733006659E5 /* BRPlayerProtocol.swift in Sources */, BFC676812E122733006659E5 /* BRPlayerProtocol.swift in Sources */,
BFC676BC2E138ABB006659E5 /* BRNewReleasesViewController.swift in Sources */,
BF692B5F2E0B812800A5C2DA /* BRTabBarItemContainer.swift in Sources */, BF692B5F2E0B812800A5C2DA /* BRTabBarItemContainer.swift in Sources */,
BF692B652E0BC53900A5C2DA /* CGMutablePath+BRRoundedCorner.swift in Sources */, BF692B652E0BC53900A5C2DA /* CGMutablePath+BRRoundedCorner.swift in Sources */,
BFC676752E0E93B3006659E5 /* BRTableViewCell.swift in Sources */, BFC676752E0E93B3006659E5 /* BRTableViewCell.swift in Sources */,
@ -776,6 +836,7 @@
BF692B092E0A775500A5C2DA /* BRLoginToken.swift in Sources */, BF692B092E0A775500A5C2DA /* BRLoginToken.swift in Sources */,
BF692AFC2E0A6F8000A5C2DA /* BRNetworkTarget.swift in Sources */, BF692AFC2E0A6F8000A5C2DA /* BRNetworkTarget.swift in Sources */,
BF692B3A2E0A8C6000A5C2DA /* BRViewController.swift in Sources */, BF692B3A2E0A8C6000A5C2DA /* BRViewController.swift in Sources */,
BFC676BE2E13A8EB006659E5 /* UIScrollView+BRRefresh.swift in Sources */,
BF692B182E0A7D8900A5C2DA /* BRToast.swift in Sources */, BF692B182E0A7D8900A5C2DA /* BRToast.swift in Sources */,
BF692B0E2E0A7AF300A5C2DA /* UserDefaults+BRAdd.swift in Sources */, BF692B0E2E0A7AF300A5C2DA /* UserDefaults+BRAdd.swift in Sources */,
BF692B582E0AAA6F00A5C2DA /* UIScreen+BRAdd.swift in Sources */, BF692B582E0AAA6F00A5C2DA /* UIScreen+BRAdd.swift in Sources */,
@ -783,6 +844,7 @@
BF692B612E0B814F00A5C2DA /* BRTabBarItemContentView.swift in Sources */, BF692B612E0B814F00A5C2DA /* BRTabBarItemContentView.swift in Sources */,
BF692B012E0A74A200A5C2DA /* BRDefine.swift in Sources */, BF692B012E0A74A200A5C2DA /* BRDefine.swift in Sources */,
BFC6767B2E0E973B006659E5 /* UIStackView+BRAdd.swift in Sources */, BFC6767B2E0E973B006659E5 /* UIStackView+BRAdd.swift in Sources */,
BFC676AB2E1372BD006659E5 /* BRHomeTop3Cell.swift in Sources */,
BFC676892E122FDD006659E5 /* BRVideoAPI.swift in Sources */, BFC676892E122FDD006659E5 /* BRVideoAPI.swift in Sources */,
BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */, BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */,
BFC676832E122CC5006659E5 /* BRPlayerViewModel.swift in Sources */, BFC676832E122CC5006659E5 /* BRPlayerViewModel.swift in Sources */,
@ -809,8 +871,10 @@
BF692B562E0AA92100A5C2DA /* BRCollectionViewCell.swift in Sources */, BF692B562E0AA92100A5C2DA /* BRCollectionViewCell.swift in Sources */,
BF692B072E0A771C00A5C2DA /* BRModel.swift in Sources */, BF692B072E0A771C00A5C2DA /* BRModel.swift in Sources */,
BF692B752E0D39D000A5C2DA /* BRListModel.swift in Sources */, BF692B752E0D39D000A5C2DA /* BRListModel.swift in Sources */,
BFC676B92E1385FC006659E5 /* BRPopularPicksSmallCell.swift in Sources */,
BF692B512E0AA8C600A5C2DA /* BRPlayerListViewController.swift in Sources */, BF692B512E0AA8C600A5C2DA /* BRPlayerListViewController.swift in Sources */,
BFC676522E0D4EFD006659E5 /* BRHomeViewModel.swift in Sources */, BFC676522E0D4EFD006659E5 /* BRHomeViewModel.swift in Sources */,
BFC676A72E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift in Sources */,
BF692B2A2E0A84F700A5C2DA /* JXUUID.m in Sources */, BF692B2A2E0A84F700A5C2DA /* JXUUID.m in Sources */,
BF692B2B2E0A84F700A5C2DA /* PDKeyChain.m in Sources */, BF692B2B2E0A84F700A5C2DA /* PDKeyChain.m in Sources */,
BFC6766B2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift in Sources */, BFC6766B2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift in Sources */,

View File

@ -48,7 +48,11 @@ class BRViewController: UIViewController {
return statusBarStyle return statusBarStyle
} }
func handleHeaderRefresh(_ completer: (() -> Void)?) {} func handleHeaderRefresh(_ completer: (() -> Void)?) {
completer?()
}
func handleFooterRefresh(_ completer: (() -> Void)?) {} func handleFooterRefresh(_ completer: (() -> Void)?) {
completer?()
}
} }

View File

@ -50,4 +50,12 @@ extension UIColor {
static func colorFF7489(alpha: CGFloat = 1) -> UIColor { static func colorFF7489(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xFF7489, alpha: alpha) return UIColor(rgb: 0xFF7489, alpha: alpha)
} }
static func color777777(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x777777, alpha: alpha)
}
static func colorE3FC37(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xE3FC37, alpha: alpha)
}
} }

View File

@ -0,0 +1,57 @@
//
// UIScrollView+BRRefresh.swift
// BeeReel
//
// Created by on 2025/7/1.
//
import UIKit
import MJRefresh
extension UIScrollView {
func br_addRefreshHeader(insetTop: CGFloat = 0, block: (() -> Void)?) {
self.mj_header = MJRefreshNormalHeader(refreshingBlock: {
block?()
})
self.mj_header?.ignoredScrollViewContentInsetTop = insetTop
}
func br_addRefreshFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
let footer = MJRefreshAutoNormalFooter(refreshingBlock: {
block?()
})
footer.ignoredScrollViewContentInsetBottom = insetBottom
self.mj_footer = footer
}
func br_addRefreshBackFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
self.mj_footer = MJRefreshBackNormalFooter(refreshingBlock: {
block?()
})
self.mj_footer?.ignoredScrollViewContentInsetBottom = insetBottom
}
func br_endHeaderRefreshing() {
self.mj_header?.endRefreshing()
}
func br_endFooterRefreshing() {
if self.mj_footer?.state == .noMoreData { return }
self.mj_footer?.endRefreshing()
}
///
func br_resetNoMoreData() {
self.mj_footer?.resetNoMoreData()
}
func br_endRefreshingWithNoMoreData() {
self.mj_footer?.endRefreshingWithNoMoreData()
}
}

View File

@ -28,5 +28,31 @@ class BRHomeAPI {
} }
} }
///
static func requestPopularPicksList(completer: ((_ list: [BRShortModel]?) -> Void)?) {
var param = BRNetworkParameters(path: "/highestPaymentAndHottestVideo")
param.method = .get
param.parameters = [
"buy_count_num" : "0",
"hottest_num" : "20"
]
BRNetwork.request(parameters: param) { (response: BRNetworkResponse<BRListModel<BRShortModel>>) in
completer?(response.data?.list)
}
}
static func requestNewReleasesList(page: Int, completer: ((_ list: [BRShortModel]?) -> Void)?) {
var param = BRNetworkParameters(path: "/newShortPlayList")
param.method = .get
param.parameters = [
"current_page" : page,
"page_size" : "20"
]
BRNetwork.request(parameters: param) { (response: BRNetworkResponse<BRListModel<BRShortModel>>) in
completer?(response.data?.list)
}
}
} }

View File

@ -117,19 +117,13 @@ struct BRNetwork {
brLog(message: parameters.parameters) brLog(message: parameters.parameters)
brLog(message: parameters.path) brLog(message: parameters.path)
let response: BRNetworkResponse<T> = _deserialize(data: tempData)
DispatchQueue.global().async { if response.code != BRNetworkCodeSucceed {
let response: BRNetworkResponse<T> = _deserialize(data: tempData) if parameters.isToast {
BRToast.show(text: response.msg)
DispatchQueue.main.async {
if response.code != BRNetworkCodeSucceed {
if parameters.isToast {
BRToast.show(text: response.msg)
}
}
completion?(response)
} }
} }
completion?(response)
} catch { } catch {
var res = BRNetworkResponse<T>() var res = BRNetworkResponse<T>()

View File

@ -10,33 +10,181 @@ import UIKit
class BRHomeTop10ViewController: BRViewController { class BRHomeTop10ViewController: BRViewController {
private lazy var dataArr: [BRShortModel] = [] private lazy var dataArr: [[BRShortModel]] = []
// private lazy var collectionView: BRCollectionView = { private lazy var collectionViewLayout: WaterfallMutiSectionFlowLayout = {
// let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: <#T##UICollectionViewLayout#>) let layout = WaterfallMutiSectionFlowLayout()
// }() layout.delegate = self
return layout
}()
private lazy var collectionView: BRCollectionView = {
let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight + 10, right: 0)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(BRHomeTop10Cell.self, forCellWithReuseIdentifier: "cell")
collectionView.register(BRHomeTop3Cell.self, forCellWithReuseIdentifier: "BRHomeTop3Cell")
return collectionView
}()
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
requestDataArr() requestDataArr()
br_setupUI()
} }
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
requestDataArr {
completer?()
}
}
} }
extension BRHomeTop10ViewController { extension BRHomeTop10ViewController {
private func requestDataArr() { private func br_setupUI() {
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalToSuperview()
make.top.equalToSuperview().offset(20)
}
}
}
//MARK: -------------- WMZPageProtocol --------------
extension BRHomeTop10ViewController: WMZPageProtocol {
func getMyScrollView() -> UIScrollView {
return self.collectionView
}
}
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
extension BRHomeTop10ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let model = self.dataArr[indexPath.section][indexPath.row]
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BRHomeTop3Cell", for: indexPath) as! BRHomeTop3Cell
cell.model = model
cell.num = indexPath.row + 1
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRHomeTop10Cell
cell.model = model
cell.num = indexPath.row + 4
return cell
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return self.dataArr.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataArr[section].count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = self.dataArr[indexPath.section][indexPath.row]
let vc = BRVideoDetailViewController()
vc.shortPlayId = model.short_play_id
self.navigationController?.pushViewController(vc, animated: true)
}
}
//MARK: -------------- WaterfallMutiSectionDelegate --------------
extension BRHomeTop10ViewController: WaterfallMutiSectionDelegate {
func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat {
if indexPath.section == 0 {
if indexPath.row == 0 {
return 240
} else {
return 115
}
}
return 126
}
func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int {
if section == 0 {
return 2
} else {
return 1
}
}
func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat {
if section == 0 {
return 10
} else {
return 12
}
}
func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat {
return 10
}
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize {
if section > 0 {
return .init(width: UIScreen.width, height: 10)
} else {
return .zero
}
}
func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets {
return .init(top: 0, left: 15, bottom: 0, right: 15)
}
}
extension BRHomeTop10ViewController {
private func requestDataArr(completer: (() -> Void)? = nil) {
BRHomeAPI.requestTop10List { [weak self] list in BRHomeAPI.requestTop10List { [weak self] list in
guard let self = self else { return } guard let self = self else { return }
guard let list = list else { return } guard let list = list else {
self.dataArr = list completer?()
return
}
self.dataArr.removeAll()
var arr1: [BRShortModel] = []
var arr2: [BRShortModel] = []
list.enumerated().forEach {
if $0 < 3 {
arr1.append($1)
} else {
arr2.append($1)
}
}
if arr1.count > 0 {
self.dataArr.append(arr1)
}
if arr2.count > 0 {
self.dataArr.append(arr2)
}
self.collectionView.reloadData()
completer?()
} }
} }

View File

@ -23,12 +23,14 @@ class BRHomeViewController: BRViewController {
return [ return [
spotlightVC, spotlightVC,
BRHomeTop10ViewController(), BRHomeTop10ViewController(),
BRViewController(), BRPopularPicksViewController(),
BRViewController(), BRNewReleasesViewController(),
BRViewController() BRViewController()
] ]
}() }()
private lazy var requestGroup = DispatchGroup()
private lazy var pageParam: WMZPageParam = { private lazy var pageParam: WMZPageParam = {
let param = WMZPageParam() let param = WMZPageParam()
param.wTitleArr = [ param.wTitleArr = [
@ -75,7 +77,7 @@ class BRHomeViewController: BRViewController {
return 0 return 0
} }
param.wCustomTabbarY = { _ in param.wCustomTabbarY = { _ in
return UIScreen.customTabBarHeight return 0
} }
@ -96,6 +98,9 @@ class BRHomeViewController: BRViewController {
let view = WMZPageView(frame: self.view.bounds, autoFix: true, param: pageParam, parentReponder: self) let view = WMZPageView(frame: self.view.bounds, autoFix: true, param: pageParam, parentReponder: self)
view.backgroundColor = .clear view.backgroundColor = .clear
view.downSc?.backgroundColor = .clear view.downSc?.backgroundColor = .clear
view.downSc?.br_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
}
return view return view
}() }()
@ -162,6 +167,25 @@ class BRHomeViewController: BRViewController {
} }
} }
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
self.requestGroup.enter()
requestHomeData { [weak self] in
self?.requestGroup.leave()
}
if let vc = self.pageView.upSc.currentVC as? BRViewController {
self.requestGroup.enter()
vc.handleHeaderRefresh { [weak self] in
self?.requestGroup.leave()
}
}
self.requestGroup.notify(queue: .main) { [weak self] in
self?.pageView.downSc?.br_endHeaderRefreshing()
}
}
} }
@ -215,21 +239,24 @@ extension BRHomeViewController {
extension BRHomeViewController { extension BRHomeViewController {
private func requestHomeData() { private func requestHomeData(completer: (() -> Void)? = nil) {
BRHomeAPI.requestHomeData { [weak self] list in BRHomeAPI.requestHomeData { [weak self] list in
guard let self = self else { return } guard let self = self else { return }
self.viewModel.homeOldDataArr = list ?? [] if let list = list {
self.viewModel.homeOldDataArr = list
self.headerView.bannerArr = self.viewModel.bannerArr self.headerView.bannerArr = self.viewModel.bannerArr
if let bannerArr = self.viewModel.bannerArr, bannerArr.count > 0 { if let bannerArr = self.viewModel.bannerArr, bannerArr.count > 0 {
self.bgImageView.isHidden = false self.bgImageView.isHidden = false
self.pageView.updateHeadView() self.pageView.updateHeadView()
} else { } else {
self.bgImageView.isHidden = true self.bgImageView.isHidden = true
}
self.spotlightVC.reloadData()
} }
self.spotlightVC.reloadData()
self.updateStatusBarStyle() self.updateStatusBarStyle()
completer?()
} }
} }

View File

@ -0,0 +1,125 @@
//
// BRNewReleasesViewController.swift
// BeeReel
//
// Created by on 2025/7/1.
//
import UIKit
class BRNewReleasesViewController: BRViewController {
private lazy var dataArr: [BRShortModel] = []
private lazy var page: Int = 1
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
let width = floor((UIScreen.width - 30 - 10) / 2)
let layout = UICollectionViewFlowLayout()
layout.itemSize = .init(width: width, height: 222)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 10
layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15)
return layout
}()
private lazy var collectionView: BRCollectionView = {
let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight + 10, right: 0)
collectionView.br_addRefreshBackFooter(insetBottom: 0) { [weak self] in
self?.handleFooterRefresh(nil)
}
collectionView.register(BRSpotlightNewCell.self, forCellWithReuseIdentifier: "cell")
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
requestDataArr(page: 1)
br_setupUI()
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
requestDataArr(page: 1) {
completer?()
}
}
override func handleFooterRefresh(_ completer: (() -> Void)?) {
requestDataArr(page: self.page + 1) { [weak self] in
self?.collectionView.br_endFooterRefreshing()
}
}
}
extension BRNewReleasesViewController {
private func br_setupUI() {
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalToSuperview().offset(20)
make.bottom.equalToSuperview()
}
}
}
//MARK: -------------- WMZPageProtocol --------------
extension BRNewReleasesViewController: WMZPageProtocol {
func getMyScrollView() -> UIScrollView {
return self.collectionView
}
}
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
extension BRNewReleasesViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRSpotlightNewCell
cell.model = self.dataArr[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArr.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = dataArr[indexPath.row]
let vc = BRVideoDetailViewController()
vc.shortPlayId = model.short_play_id
self.navigationController?.pushViewController(vc, animated: true)
}
}
extension BRNewReleasesViewController {
private func requestDataArr(page: Int, completer: (() -> Void)? = nil) {
BRHomeAPI.requestNewReleasesList(page: page) { [weak self] list in
guard let self = self else { return }
if let list = list {
if page == 1 {
self.dataArr.removeAll()
}
self.dataArr += list
self.page = page
self.collectionView.reloadData()
}
completer?()
}
}
}

View File

@ -0,0 +1,174 @@
//
// BRPopularPicksViewController.swift
// BeeReel
//
// Created by on 2025/7/1.
//
import UIKit
class BRPopularPicksViewController: BRViewController {
private lazy var dataArr: [BRShortModel] = []
private lazy var contentView: UIView = {
let view = UIView()
view.backgroundColor = .colorFFFFFF()
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
return view
}()
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = .init(width: UIScreen.width - 90 - 20, height: 196)
layout.sectionInset = .init(top: 10, left: 10, bottom: 0, right: 10)
layout.minimumLineSpacing = 10
return layout
}()
private lazy var collectionView: BRCollectionView = {
let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.contentInset = .init(top: 0, left: 0, bottom: 10, right: 0)
collectionView.register(BRPopularPicksCell.self, forCellWithReuseIdentifier: "cell")
return collectionView
}()
private lazy var smallCollectionViewLayout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = .init(width: 44, height: 58)
layout.minimumLineSpacing = 10
return layout
}()
private lazy var smallCollectionView: BRCollectionView = {
let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: smallCollectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.showsVerticalScrollIndicator = false
collectionView.register(BRPopularPicksSmallCell.self, forCellWithReuseIdentifier: "cell")
return collectionView
}()
private lazy var topButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "top_button_01"), for: .normal)
button.addTarget(self, action: #selector(handleTopButton), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
br_setupUI()
requestDataArr()
}
@objc private func handleTopButton() {
collectionView.scrollToTop(animated: true)
smallCollectionView.scrollToTop(animated: true)
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
requestDataArr {
completer?()
}
}
}
extension BRPopularPicksViewController {
private func br_setupUI() {
view.addSubview(contentView)
contentView.addSubview(collectionView)
view.addSubview(smallCollectionView)
view.addSubview(topButton)
contentView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-75)
make.top.equalToSuperview().offset(20)
make.bottom.equalToSuperview().offset(-(UIScreen.customTabBarHeight + 15))
}
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
smallCollectionView.snp.makeConstraints { make in
make.top.equalTo(contentView)
make.right.equalToSuperview().offset(-15)
make.width.equalTo(self.smallCollectionViewLayout.itemSize.width)
// make.bottom.equalTo(contentView)
make.bottom.equalTo(topButton.snp.top).offset(-10)
}
topButton.snp.makeConstraints { make in
make.centerX.equalTo(smallCollectionView)
make.bottom.equalTo(contentView)
}
}
}
//MARK: -------------- WMZPageProtocol --------------
extension BRPopularPicksViewController: WMZPageProtocol {
func getMyScrollViews() -> [UIScrollView] {
return [self.collectionView, self.smallCollectionView]
}
}
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
extension BRPopularPicksViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let model = self.dataArr[indexPath.row]
if collectionView == self.collectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRPopularPicksCell
cell.model = model
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRPopularPicksSmallCell
cell.model = model
return cell
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataArr.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = self.dataArr[indexPath.row]
let vc = BRVideoDetailViewController()
vc.shortPlayId = model.short_play_id
self.navigationController?.pushViewController(vc, animated: true)
}
}
extension BRPopularPicksViewController {
private func requestDataArr(completer: (() -> Void)? = nil) {
BRHomeAPI.requestPopularPicksList { [weak self] list in
guard let self = self else { return }
if let list = list {
self.dataArr = list
self.collectionView.reloadData()
self.smallCollectionView.reloadData()
}
completer?()
}
}
}

View File

@ -15,6 +15,7 @@ class BRSpotlightViewViewController: BRViewController, WMZPageProtocol {
let tableView = BRTableView(frame: .zero, style: .plain) let tableView = BRTableView(frame: .zero, style: .plain)
tableView.delegate = self tableView.delegate = self
tableView.dataSource = self tableView.dataSource = self
tableView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight, right: 0)
tableView.register(BRSpotlightMainBaseCell.self, forCellReuseIdentifier: "cell") tableView.register(BRSpotlightMainBaseCell.self, forCellReuseIdentifier: "cell")
tableView.register(BRSpotlightHotMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.v3_recommand.rawValue) tableView.register(BRSpotlightHotMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.v3_recommand.rawValue)
tableView.register(BRSpotlightTopMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.week_ranking.rawValue) tableView.register(BRSpotlightTopMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.week_ranking.rawValue)
@ -46,7 +47,7 @@ extension BRSpotlightViewViewController {
tableView.snp.makeConstraints { make in tableView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview() make.left.right.bottom.equalToSuperview()
make.top.equalToSuperview().offset(15) make.top.equalToSuperview().offset(20)
} }
} }

View File

@ -45,7 +45,7 @@ class BRShortModel: BRModel, SmartCodable {
var all_coins: String? var all_coins: String?
var buy_type: String? var buy_type: String?
var collect_total: Int? var collect_total: Int?
var vp_description: String? var br_description: String?
var episode_total: Int? var episode_total: Int?
var horizontally_img: String? var horizontally_img: String?
var image_url: String? var image_url: String?
@ -70,12 +70,12 @@ class BRShortModel: BRModel, SmartCodable {
@IgnoredKey @IgnoredKey
var titleAttributedString: NSAttributedString? var titleAttributedString: NSAttributedString?
@IgnoredKey @IgnoredKey
var vp_isSelected: Bool? var br_isSelected: Bool?
static func mappingForKey() -> [SmartKeyTransformer]? { static func mappingForKey() -> [SmartKeyTransformer]? {
return [ return [
CodingKeys.vp_description <--- ["description", "short_video_description"], CodingKeys.br_description <--- ["description", "short_video_description"],
CodingKeys.name <--- ["short_video_title", "name"] CodingKeys.name <--- ["short_video_title", "name"]
] ]
} }

View File

@ -0,0 +1,125 @@
//
// BRPopularPicksCell.swift
// BeeReel
//
// Created by on 2025/7/1.
//
import UIKit
class BRPopularPicksCell: BRCollectionViewCell {
var model: BRShortModel? {
didSet {
coverImageView.br_setImage(url: model?.image_url)
titleLabel.text = model?.name
categoryLabel.text = model?.category?.first
desLabel.text = model?.br_description
hotView.setNeedsUpdateConfiguration()
}
}
private lazy var coverImageView: BRImageView = {
let imageView = BRImageView()
imageView.layer.cornerRadius = 8
imageView.layer.masksToBounds = true
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .color1C1C1C()
label.numberOfLines = 3
return label
}()
private lazy var categoryLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 10)
label.textColor = .color899D00()
return label
}()
private lazy var desLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 10)
label.textColor = .color777777()
label.numberOfLines = 4
return label
}()
private lazy var hotView: UIButton = {
var config = UIButton.Configuration.plain()
config.image = UIImage(named: "hot_icon_02")
config.imagePlacement = .leading
config.imagePadding = 2
config.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0)
let button = UIButton(configuration: config)
button.isUserInteractionEnabled = false
button.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
let count = model?.watch_total ?? 0
var string = "\(count)"
if count > 100 {
string = String(format: "%.1fk", Float(count) / 1000)
}
button.configuration?.attributedTitle = AttributedString.br_createAttributedString(string: string, color: .colorFF7489(), font: .fontRegular(ofSize: 10))
}
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
br_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension BRPopularPicksCell {
private func br_setupUI() {
contentView.addSubview(coverImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(categoryLabel)
contentView.addSubview(desLabel)
contentView.addSubview(hotView)
coverImageView.snp.makeConstraints { make in
make.left.top.bottom.equalToSuperview()
make.width.equalTo(152)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(coverImageView.snp.right).offset(10)
make.right.lessThanOrEqualToSuperview().offset(-10)
make.centerY.equalTo(self.contentView.snp.top).offset(30)
}
categoryLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalToSuperview().offset(75)
}
desLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.right.lessThanOrEqualToSuperview().offset(-10)
make.centerY.equalTo(self.contentView.snp.top).offset(27.5 + 94)
}
hotView.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.bottom.equalToSuperview().offset(-17)
}
}
}

View File

@ -0,0 +1,38 @@
//
// BRPopularPicksSmallCell.swift
// BeeReel
//
// Created by on 2025/7/1.
//
import UIKit
class BRPopularPicksSmallCell: BRCollectionViewCell {
var model: BRShortModel? {
didSet {
coverImageView.br_setImage(url: model?.image_url)
}
}
private lazy var coverImageView: BRImageView = {
let imageView = BRImageView()
imageView.layer.cornerRadius = 4
imageView.layer.masksToBounds = true
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(coverImageView)
coverImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -20,6 +20,23 @@ class BRSpotlightTopCell: BRCollectionViewCell {
} }
} }
var num: Int = 0 {
didSet {
switch num {
case 1:
numView.image = UIImage(named: "number_icon_01")
numView.isHidden = false
case 2:
numView.image = UIImage(named: "number_icon_02")
numView.isHidden = false
case 3:
numView.image = UIImage(named: "number_icon_03")
numView.isHidden = false
default:
numView.isHidden = true
}
}
}
private lazy var coverImageView: BRImageView = { private lazy var coverImageView: BRImageView = {
let imageView = BRImageView() let imageView = BRImageView()
@ -41,6 +58,11 @@ class BRSpotlightTopCell: BRCollectionViewCell {
return imageView return imageView
}() }()
private lazy var numView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
private lazy var titleLabel: UILabel = { private lazy var titleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontMedium(ofSize: 12) label.font = .fontMedium(ofSize: 12)
@ -98,6 +120,7 @@ extension BRSpotlightTopCell {
contentView.addSubview(coverImageView) contentView.addSubview(coverImageView)
coverImageView.addSubview(numView)
coverImageView.addSubview(coverMarkView) coverImageView.addSubview(coverMarkView)
contentView.addSubview(playImageView) contentView.addSubview(playImageView)
coverImageView.addSubview(textBgView) coverImageView.addSubview(textBgView)
@ -109,6 +132,11 @@ extension BRSpotlightTopCell {
make.edges.equalToSuperview() make.edges.equalToSuperview()
} }
numView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(10)
make.top.equalToSuperview().offset(10)
}
coverMarkView.snp.makeConstraints { make in coverMarkView.snp.makeConstraints { make in
make.right.bottom.equalToSuperview() make.right.bottom.equalToSuperview()
} }

View File

@ -64,6 +64,7 @@ extension BRSpotlightTopMainCell: UICollectionViewDelegate, UICollectionViewData
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRSpotlightTopCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRSpotlightTopCell
cell.model = self.moduleItem?.list?[indexPath.row] cell.model = self.moduleItem?.list?[indexPath.row]
cell.num = indexPath.row + 1
return cell return cell
} }

View File

@ -0,0 +1,167 @@
//
// BRHomeTop10Cell.swift
// BeeReel
//
// Created by on 2025/6/30.
//
import UIKit
class BRHomeTop10Cell: BRCollectionViewCell {
var model: BRShortModel? {
didSet {
coverImageView.br_setImage(url: model?.image_url)
titleLabel.text = model?.name
categoryLabel.text = model?.category?.first
desLabel.text = model?.br_description
hotView.setNeedsUpdateConfiguration()
}
}
var num: Int = 0 {
didSet {
numLabel.text = "\(num)"
}
}
private lazy var bgImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "top_bg_image_01"))
return imageView
}()
private lazy var coverImageView: BRImageView = {
let imageView = BRImageView()
imageView.layer.cornerRadius = 8
imageView.layer.masksToBounds = true
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .color1C1C1C()
return label
}()
private lazy var categoryLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 10)
label.textColor = .color899D00()
return label
}()
private lazy var desLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 2
label.font = .fontRegular(ofSize: 10)
label.textColor = .color777777()
return label
}()
private lazy var hotView: UIButton = {
var config = UIButton.Configuration.plain()
config.image = UIImage(named: "hot_icon_02")
config.imagePlacement = .leading
config.imagePadding = 2
config.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0)
let button = UIButton(configuration: config)
button.isUserInteractionEnabled = false
button.configurationUpdateHandler = { [weak self] button in
guard let self = self else { return }
let count = model?.watch_total ?? 0
var string = "\(count)"
if count > 100 {
string = String(format: "%.1fk", Float(count) / 1000)
}
button.configuration?.attributedTitle = AttributedString.br_createAttributedString(string: string, color: .colorFF7489(), font: .fontRegular(ofSize: 10))
}
return button
}()
private lazy var numBgView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "number_bg_icon_01"))
return imageView
}()
private lazy var numLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 15)
label.textColor = .color000000()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
br_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension BRHomeTop10Cell {
private func br_setupUI() {
contentView.addSubview(bgImageView)
bgImageView.addSubview(coverImageView)
bgImageView.addSubview(titleLabel)
bgImageView.addSubview(categoryLabel)
bgImageView.addSubview(desLabel)
bgImageView.addSubview(hotView)
bgImageView.addSubview(numBgView)
bgImageView.addSubview(numLabel)
bgImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
coverImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(7)
make.width.equalTo(90)
make.height.equalTo(112)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(coverImageView.snp.right).offset(20)
make.top.equalToSuperview().offset(16)
make.right.lessThanOrEqualToSuperview().offset(-48)
}
categoryLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalToSuperview().offset(41)
}
desLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalToSuperview().offset(60)
make.right.lessThanOrEqualToSuperview().offset(-48)
}
hotView.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.bottom.equalToSuperview().offset(-17)
}
numBgView.snp.makeConstraints { make in
make.centerX.equalTo(self.bgImageView.snp.right).offset(-15)
make.centerY.equalToSuperview().offset(-3)
}
numLabel.snp.makeConstraints { make in
make.centerX.equalTo(numBgView)
make.centerY.equalToSuperview().offset(3)
}
}
}

View File

@ -0,0 +1,110 @@
//
// BRHomeTop3Cell.swift
// BeeReel
//
// Created by on 2025/6/30.
//
import UIKit
class BRHomeTop3Cell: BRCollectionViewCell {
var model: BRShortModel? {
didSet {
coverImageView.br_setImage(url: model?.image_url)
}
}
var num: Int = 0 {
didSet {
numLabel.text = "NO.\(num)"
if num == 1 {
coverImageView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(32)
}
} else {
coverImageView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(28)
}
}
}
}
private lazy var coverImageView: BRImageView = {
let imageView = BRImageView()
imageView.layer.cornerRadius = 8
imageView.layer.masksToBounds = true
return imageView
}()
private lazy var numLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorE3FC37()
return label
}()
private lazy var numIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "num_icon_01"))
return imageView
}()
private lazy var dotView: UIView = {
let view = UIView()
view.backgroundColor = .colorE3FC37()
view.layer.cornerRadius = 3
view.layer.masksToBounds = true
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.backgroundColor = .color1C1C1C()
self.contentView.layer.cornerRadius = 12
self.contentView.layer.masksToBounds = true
br_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension BRHomeTop3Cell {
private func br_setupUI() {
contentView.addSubview(coverImageView)
contentView.addSubview(dotView)
contentView.addSubview(numLabel)
contentView.addSubview(numIconImageView)
coverImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(5)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-5)
make.top.equalToSuperview().offset(32)
}
dotView.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-5)
make.top.equalToSuperview().offset(12)
make.width.height.equalTo(6)
}
numLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(5)
make.centerY.equalTo(dotView)
}
numIconImageView.snp.makeConstraints { make in
make.centerY.equalTo(numLabel)
make.left.equalTo(numLabel.snp.right).offset(10)
}
}
}

View File

@ -5,10 +5,15 @@
// Created by on 2025/6/25. // Created by on 2025/6/25.
// //
import MJRefresh
extension AppDelegate { extension AppDelegate {
func addConfig() { func addConfig() {
UIView.vp_Awake() UIView.vp_Awake()
//
MJRefreshConfig.default.languageCode = BRLocalizedManager.manager.mjLocalizedKey
} }
} }

View File

@ -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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Ellipse 9@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Ellipse 9@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "金 1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "金 1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "金 2@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "金 2@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "铜 1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "铜 1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 21@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 21@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

View File

@ -0,0 +1,44 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "bg@2x.png",
"idiom" : "universal",
"resizing" : {
"cap-insets" : {
"left" : 300,
"right" : 94
},
"center" : {
"mode" : "tile",
"width" : 1
},
"mode" : "3-part-horizontal"
},
"scale" : "2x"
},
{
"filename" : "bg@3x.png",
"idiom" : "universal",
"resizing" : {
"cap-insets" : {
"left" : 431,
"right" : 127
},
"center" : {
"mode" : "tile",
"width" : 1
},
"mode" : "3-part-horizontal"
},
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,193 @@
//
// WaterfallMutiSectionFlowLayout.swift
// gymbo
//
// Created by drogan Zheng on 2020/5/7.
// Copyright © 2020 Gymbo.co. All rights reserved.
// https://github.com/RoganZheng/WaterfallMultiSectionFlowLayout
//
import UIKit
@objc protocol WaterfallMutiSectionDelegate: NSObjectProtocol {
// delegate
/// collectionItem
func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat
// delegate
/// section 2
@objc optional func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int
/// header0
@objc optional func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize
/// footer0
@objc optional func referenceSizeForFooter(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize
/// section 0
@objc optional func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets
/// section item0
@objc optional func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat
/// section item0
@objc optional func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat
/// sectionheadersectionfooter0
@objc optional func spacingWithLastSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat
}
class WaterfallMutiSectionFlowLayout: UICollectionViewFlowLayout {
weak var delegate: WaterfallMutiSectionDelegate?
private var sectionInsets: UIEdgeInsets = .zero
private var columnCount: Int = 2
private var lineSpacing: CGFloat = 0
private var interitemSpacing: CGFloat = 0
private var headerSize: CGSize = .zero
private var footerSize: CGSize = .zero
//attribute
private var attrsArray: [UICollectionViewLayoutAttributes] = []
//section
private var columnHeights: [CGFloat] = []
//collectionViewContent
private var contentHeight: CGFloat = 0
//section
private var lastContentHeight: CGFloat = 0
//sectionheadersectionfooter
private var spacingWithLastSection: CGFloat = 0
override func prepare() {
super.prepare()
self.contentHeight = 0
self.lastContentHeight = 0
self.spacingWithLastSection = 0
self.lineSpacing = 0
self.sectionInsets = .zero
self.headerSize = .zero
self.footerSize = .zero
self.columnHeights.removeAll()
self.attrsArray.removeAll()
let sectionCount = self.collectionView!.numberOfSections
// section
for idx in 0..<sectionCount {
let indexPath = IndexPath(item: 0, section: idx)
if let columnCount = self.delegate?.columnNumber?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.columnCount = columnCount
}
if let inset = self.delegate?.insetForSection?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.sectionInsets = inset
}
if let spacingLastSection = self.delegate?.spacingWithLastSection?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.spacingWithLastSection = spacingLastSection
}
// header
let itemCount = self.collectionView!.numberOfItems(inSection: idx)
let headerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath)
if let header = headerAttri {
self.attrsArray.append(header)
self.columnHeights.removeAll()
}
self.lastContentHeight = self.contentHeight
// y
for _ in 0..<self.columnCount {
self.columnHeights.append(self.contentHeight)
}
// item
for item in 0..<itemCount {
let indexPat = IndexPath(item: item, section: idx)
let attri = self.layoutAttributesForItem(at: indexPat)
if let attri = attri {
self.attrsArray.append(attri)
}
}
// footer
let footerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, at: indexPath)
if let footer = footerAttri {
self.attrsArray.append(footer)
}
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return self.attrsArray
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
if let column = self.delegate?.columnNumber?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.columnCount = column
}
if let lineSpacing = self.delegate?.lineSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.lineSpacing = lineSpacing
}
if let interitem = self.delegate?.interitemSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.interitemSpacing = interitem
}
let attri = UICollectionViewLayoutAttributes(forCellWith: indexPath)
let weight = self.collectionView!.frame.size.width
let itemSpacing = CGFloat(self.columnCount - 1) * self.interitemSpacing
let allWeight = weight - self.sectionInsets.left - self.sectionInsets.right - itemSpacing
let cellWeight = allWeight / CGFloat(self.columnCount)
let cellHeight: CGFloat = (self.delegate?.heightForRowAtIndexPath(collectionView: self.collectionView!, layout: self, indexPath: indexPath, itemWidth: cellWeight))!
var tmpMinColumn = 0
var minColumnHeight = self.columnHeights[0]
for i in 0..<self.columnCount {
let columnH = self.columnHeights[i]
if minColumnHeight > columnH {
minColumnHeight = columnH
tmpMinColumn = i
}
}
let cellX = self.sectionInsets.left + CGFloat(tmpMinColumn) * (cellWeight + self.interitemSpacing)
var cellY: CGFloat = 0
cellY = minColumnHeight
if cellY != self.lastContentHeight {
cellY += self.lineSpacing
}
if self.contentHeight < minColumnHeight {
self.contentHeight = minColumnHeight
}
attri.frame = CGRect(x: cellX, y: cellY, width: cellWeight, height: cellHeight)
self.columnHeights[tmpMinColumn] = attri.frame.maxY
//
for i in 0..<self.columnHeights.count {
if self.contentHeight < self.columnHeights[i] {
self.contentHeight = self.columnHeights[i]
}
}
return attri
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attri = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)
if elementKind == UICollectionView.elementKindSectionHeader {
if let headerSize = self.delegate?.referenceSizeForHeader?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.headerSize = headerSize
}
self.contentHeight += self.spacingWithLastSection
attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.headerSize.width, height: self.headerSize.height)
self.contentHeight += self.headerSize.height
self.contentHeight += self.sectionInsets.top
} else if elementKind == UICollectionView.elementKindSectionFooter {
if let footerSize = self.delegate?.referenceSizeForFooter?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.footerSize = footerSize
}
self.contentHeight += self.sectionInsets.bottom
attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.footerSize.width, height: self.footerSize.height)
self.contentHeight += self.footerSize.height
}
return attri
}
override var collectionViewContentSize: CGSize {
return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight)
}
}

View File

@ -27,6 +27,6 @@ target 'BeeReel' do
pod 'YYCategories' pod 'YYCategories'
pod 'YYText' pod 'YYText'
pod 'FSPagerView' #banner pod 'FSPagerView' #banner
pod 'MJRefresh' #刷新控件
end end