This commit is contained in:
zjx 2025-07-16 17:45:06 +08:00
parent 3d8dfd2fe8
commit 108bf3141b
23 changed files with 290 additions and 4 deletions

View File

@ -62,4 +62,8 @@ extension UIColor {
static func color5A5D45(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0x5A5D45, alpha: alpha)
}
static func colorFFFDF9(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xFFFDF9, alpha: alpha)
}
}

View File

@ -24,6 +24,40 @@ class BRExploreViewController: BRPlayerListViewController {
return CGSize(width: width, height: height)
}
private lazy var titleImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "explore_title_icon"))
return imageView
}()
private lazy var searchButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "search_icon_01"), for: .normal)
return button
}()
private lazy var videoNameLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 12)
label.textColor = .colorFFFDF9()
return label
}()
private lazy var episodeButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "episode_icon_01"), for: .normal)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
return button
}()
private lazy var favoriteButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "favorite_icon_02"), for: .normal)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = .all
@ -67,12 +101,44 @@ extension BRExploreViewController {
self.collectionView.layer.cornerRadius = 20
self.collectionView.layer.masksToBounds = true
view.addSubview(titleImageView)
view.addSubview(searchButton)
view.addSubview(episodeButton)
view.addSubview(favoriteButton)
view.addSubview(videoNameLabel)
self.collectionView.snp.remakeConstraints { make in
make.left.equalToSuperview().offset(15)
make.top.equalToSuperview().offset(UIScreen.statusBarHeight + 50)
make.width.equalTo(contentSize.width)
make.height.equalTo(contentSize.height)
}
titleImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.bottom.equalTo(collectionView.snp.top).offset(-15)
}
searchButton.snp.makeConstraints { make in
make.centerY.equalTo(titleImageView)
make.right.equalToSuperview().offset(-15)
}
episodeButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-15)
make.top.equalTo(collectionView.snp.bottom).offset(10)
}
favoriteButton.snp.makeConstraints { make in
make.centerY.equalTo(episodeButton)
make.right.equalTo(episodeButton.snp.left).offset(-40)
}
videoNameLabel.snp.makeConstraints { make in
make.centerY.equalTo(episodeButton)
make.left.equalToSuperview().offset(15)
make.right.lessThanOrEqualTo(favoriteButton.snp.left).offset(-25)
}
}
}
@ -94,6 +160,10 @@ extension BRExploreViewController: BRPlayerListViewControllerDelegate, BRPlayerL
func br_playerListViewController(_ viewController: BRPlayerListViewController, _ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArr.count
}
func br_playerListViewController(_ viewController: BRPlayerListViewController, didChangeIndexPathForVisible indexPath: IndexPath) {
videoNameLabel.text = self.viewModel.currentPlayer?.shortModel?.name
}
}

View File

@ -88,6 +88,10 @@ class BRPlayerListViewController: BRViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.statusBarStyle = .lightContent
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willResignActiveNotification), name: UIApplication.willResignActiveNotification, object: nil)
br_setupUI()
}
@ -131,6 +135,11 @@ class BRPlayerListViewController: BRViewController {
// }
}
func pause() {
self.viewModel.currentPlayer?.pause()
self.viewModel.isPlaying = false
}
func reloadData(completion: (() -> Void)? = nil) {
UIView.performWithoutAnimation {
@ -276,6 +285,13 @@ extension BRPlayerListViewController: BRPlayerViewModelDelegate {
scrollToNextEpisode()
}
func br_switchPlayAndPause(viewModel: BRPlayerViewModel) {
if self.viewModel.isPlaying {
self.pause()
} else {
self.play()
}
}
}
@ -332,3 +348,19 @@ extension BRPlayerListViewController {
return BRPlayerCache.prefetch(urlString: url)
}
}
//MARK: -------------- --------------
extension BRPlayerListViewController {
@objc func didBecomeActiveNotification() {
if self.viewModel.isPlaying && isDidAppear {
self.viewModel.currentPlayer?.start()
}
}
@objc func willResignActiveNotification() {
self.viewModel.currentPlayer?.pause()
}
}

View File

@ -10,6 +10,8 @@ import UIKit
@objc protocol BRPlayerControlProtocol {
var isCurrent: Bool { get set }
///
func singleTapEvent()

View File

@ -11,6 +11,7 @@ import UIKit
var videoInfo: BRVideoInfoModel? { get set }
var shortModel: BRShortModel? { get set }
var isCurrent: Bool { get set }

View File

@ -16,7 +16,7 @@ class BRPlayerControlView: UIView, BRPlayerControlProtocol {
weak var viewModel: BRPlayerViewModel? {
didSet {
self.viewModel?.addObserver(self, forKeyPath: "isPlaying", context: nil)
}
}
@ -32,18 +32,73 @@ class BRPlayerControlView: UIView, BRPlayerControlProtocol {
}
}
private lazy var playIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "play_icon_05"))
return imageView
}()
deinit {
self.viewModel?.removeObserver(self, forKeyPath: "isPlaying")
}
override init(frame: CGRect) {
super.init(frame: frame)
br_setupUI()
self.updatePlayIconState()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: BRPlayerControlProtocol
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "isPlaying" {
self.updatePlayIconState()
}
}
//MARK: BRPlayerControlProtocol
var isCurrent: Bool = false {
didSet {
self.updatePlayIconState()
}
}
func singleTapEvent() {
self.viewModel?.switchPlayAndPause()
}
}
extension BRPlayerControlView {
private func br_setupUI() {
addSubview(self.playIconImageView)
self.playIconImageView.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
}
extension BRPlayerControlView {
private func updatePlayIconState() {
if isCurrent == true, self.viewModel?.isPlaying != true {
self.playIconImageView.isHidden = false
} else {
self.playIconImageView.isHidden = true
}
}
}

View File

@ -30,7 +30,11 @@ class BRPlayerListCell: BRCollectionViewCell, BRPlayerProtocol {
}
}
var isCurrent: Bool = false
var isCurrent: Bool = false {
didSet {
self.controlView.isCurrent = isCurrent
}
}
var duration: Int = 0
@ -68,7 +72,7 @@ class BRPlayerListCell: BRCollectionViewCell, BRPlayerProtocol {
}
private lazy var player: BRPlayer = {
let player = BRPlayer(controlView: nil)
let player = BRPlayer(controlView: self.controlView)
player.playerView = self.playerView
player.delegate = self

View File

@ -11,6 +11,8 @@ import UIKit
@objc protocol BRPlayerViewModelDelegate {
@objc optional func br_currentVideoPlayFinish(viewModel: BRPlayerViewModel)
@objc optional func br_switchPlayAndPause(viewModel: BRPlayerViewModel)
}
@ -42,4 +44,10 @@ extension BRPlayerViewModel {
self.delegate?.br_currentVideoPlayFinish?(viewModel: self)
}
///
func switchPlayAndPause() {
self.delegate?.br_switchPlayAndPause?(viewModel: self)
}
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB