From 5381371839d896c7ff589f94365e76697ab18148 Mon Sep 17 00:00:00 2001 From: wenlei Date: Sat, 2 Mar 2024 19:08:26 +0800 Subject: [PATCH] Refactor the message module, the focus module --- .../IndieMusic.xcodeproj/project.pbxproj | 16 ++ .../Common/NavigationController.swift | 50 ++-- IndieMusic/IndieMusic/Configs/Configs.swift | 4 +- .../IndieMusic/Managers/AudioManager.swift | 2 + IndieMusic/IndieMusic/Models/Followers.swift | 7 +- IndieMusic/IndieMusic/Models/Message.swift | 18 +- .../Modules/Home/HomeTabBarController.swift | 191 +++----------- .../Modules/Home/HomeViewController.swift | 19 +- .../JournalDetailController.swift | 19 +- .../JournalDetail/JournalDetailView.swift | 26 +- .../Message/MessageViewController.swift | 213 +++++++++------- .../Modules/Message/MessageViewModel.swift | 108 ++++---- .../Message/OtherMessageViewController.swift | 147 +++++++++++ .../PrivateMessageViewController.swift | 216 ++++++++++++++++ .../Modules/Mine/MineViewController.swift | 2 +- .../Followers/BlackListViewController.swift | 218 ++++++++++++++++ .../Followers/FollowersViewController.swift | 171 ++++++++----- .../Followers/FollowersViewModel.swift | 67 ++--- .../Followers/MyFollowersViewController.swift | 237 ++++++++++++++++++ .../Modules/Player/PlayerTabBar.swift | 29 ++- .../Modules/Player/PlayerView.swift | 4 +- .../Modules/Player/PlayerViewController.swift | 37 +-- .../Modules/Player/PlayerViewModel.swift | 13 - .../SongResultsViewController.swift | 1 - .../Modules/Search/SearchViewController.swift | 2 +- 25 files changed, 1294 insertions(+), 523 deletions(-) create mode 100644 IndieMusic/IndieMusic/Modules/Message/OtherMessageViewController.swift create mode 100644 IndieMusic/IndieMusic/Modules/Message/PrivateMessageViewController.swift create mode 100644 IndieMusic/IndieMusic/Modules/Personal/Followers/BlackListViewController.swift create mode 100644 IndieMusic/IndieMusic/Modules/Personal/Followers/MyFollowersViewController.swift diff --git a/IndieMusic/IndieMusic.xcodeproj/project.pbxproj b/IndieMusic/IndieMusic.xcodeproj/project.pbxproj index 8959ec4..f1cf067 100644 --- a/IndieMusic/IndieMusic.xcodeproj/project.pbxproj +++ b/IndieMusic/IndieMusic.xcodeproj/project.pbxproj @@ -25,6 +25,10 @@ 770FC3F62B92F4380023DE28 /* AVPlayer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3F22B92F4380023DE28 /* AVPlayer+Rx.swift */; }; 770FC3F72B92F4380023DE28 /* AVPlayerItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3F32B92F4380023DE28 /* AVPlayerItem+Rx.swift */; }; 770FC3F82B92F4380023DE28 /* AVPlayerLayer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3F42B92F4380023DE28 /* AVPlayerLayer+Rx.swift */; }; + 770FC3FA2B9319FC0023DE28 /* PrivateMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3F92B9319FC0023DE28 /* PrivateMessageViewController.swift */; }; + 770FC3FC2B931A370023DE28 /* OtherMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3FB2B931A370023DE28 /* OtherMessageViewController.swift */; }; + 770FC3FE2B9325B60023DE28 /* MyFollowersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3FD2B9325B60023DE28 /* MyFollowersViewController.swift */; }; + 770FC4002B9327E20023DE28 /* BlackListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770FC3FF2B9327E20023DE28 /* BlackListViewController.swift */; }; 771233EC2B6B6476009FAF01 /* UIButton+IndieMusic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 771233EB2B6B6476009FAF01 /* UIButton+IndieMusic.swift */; }; 771233EE2B6B8CE6009FAF01 /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 771233ED2B6B8CE6009FAF01 /* NavigationBar.swift */; }; 77165D742B464493002AE0A5 /* BarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77165D732B464493002AE0A5 /* BarButtonItem.swift */; }; @@ -293,6 +297,10 @@ 770FC3F22B92F4380023DE28 /* AVPlayer+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVPlayer+Rx.swift"; sourceTree = ""; }; 770FC3F32B92F4380023DE28 /* AVPlayerItem+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVPlayerItem+Rx.swift"; sourceTree = ""; }; 770FC3F42B92F4380023DE28 /* AVPlayerLayer+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVPlayerLayer+Rx.swift"; sourceTree = ""; }; + 770FC3F92B9319FC0023DE28 /* PrivateMessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateMessageViewController.swift; sourceTree = ""; }; + 770FC3FB2B931A370023DE28 /* OtherMessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherMessageViewController.swift; sourceTree = ""; }; + 770FC3FD2B9325B60023DE28 /* MyFollowersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyFollowersViewController.swift; sourceTree = ""; }; + 770FC3FF2B9327E20023DE28 /* BlackListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlackListViewController.swift; sourceTree = ""; }; 771233EB2B6B6476009FAF01 /* UIButton+IndieMusic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+IndieMusic.swift"; sourceTree = ""; }; 771233ED2B6B8CE6009FAF01 /* NavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBar.swift; sourceTree = ""; }; 77165D732B464493002AE0A5 /* BarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarButtonItem.swift; sourceTree = ""; }; @@ -696,6 +704,8 @@ children = ( 77C9B9DA2B4BC40F0006C83F /* FollowersViewController.swift */, 77C9B9DC2B4BC5D20006C83F /* FollowersViewModel.swift */, + 770FC3FD2B9325B60023DE28 /* MyFollowersViewController.swift */, + 770FC3FF2B9327E20023DE28 /* BlackListViewController.swift */, ); path = Followers; sourceTree = ""; @@ -1148,6 +1158,8 @@ children = ( 77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */, 77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */, + 770FC3F92B9319FC0023DE28 /* PrivateMessageViewController.swift */, + 770FC3FB2B931A370023DE28 /* OtherMessageViewController.swift */, ); path = Message; sourceTree = ""; @@ -1441,6 +1453,7 @@ 77FA0B302B0C4D5A00404C5E /* ShareActionController.swift in Sources */, 778B8AA82AF8ED0E0034AFD4 /* Color.swift in Sources */, 770228EB2B55174D00E07F7A /* InternationalNumberViewModel.swift in Sources */, + 770FC3FA2B9319FC0023DE28 /* PrivateMessageViewController.swift in Sources */, 778B8AAE2AF8ED0E0034AFD4 /* TextView.swift in Sources */, 778B8A9B2AF8ECFC0034AFD4 /* AuthManager.swift in Sources */, 778B8AAF2AF8ED0E0034AFD4 /* UIColor+IndieMusic.swift in Sources */, @@ -1495,6 +1508,7 @@ 7773EBFA2B8B3D4D0054CFE6 /* CircularIndicatorView.swift in Sources */, 7751D37A2B450BB100F1F2BD /* AgreementViewController.swift in Sources */, 778B8AAB2AF8ED0E0034AFD4 /* UIView+Borders.swift in Sources */, + 770FC3FC2B931A370023DE28 /* OtherMessageViewController.swift in Sources */, 778B8AC12AF8ED280034AFD4 /* TableView.swift in Sources */, 778B8A9C2AF8ECFC0034AFD4 /* LogManager.swift in Sources */, 778B8A992AF8ECFC0034AFD4 /* Reachability.swift in Sources */, @@ -1528,6 +1542,7 @@ 778B8A862AF8ECE50034AFD4 /* SearchViewModel.swift in Sources */, 77C9B9DD2B4BC5D20006C83F /* FollowersViewModel.swift in Sources */, 778B8A802AF8ECE50034AFD4 /* MineViewController.swift in Sources */, + 770FC3FE2B9325B60023DE28 /* MyFollowersViewController.swift in Sources */, 770FC3EF2B92C8130023DE28 /* Array+IndieMusic.swift in Sources */, 778B8A8F2AF8ECF20034AFD4 /* EmptyModel.swift in Sources */, 778B8ABD2AF8ED280034AFD4 /* View.swift in Sources */, @@ -1603,6 +1618,7 @@ 77A60D862B5B97C300D4E435 /* CachingAVURLAsset.swift in Sources */, 778B8A9A2AF8ECFC0034AFD4 /* AudioManager.swift in Sources */, 774A180E2B07000C00F56DF1 /* JournalDetailView.swift in Sources */, + 770FC4002B9327E20023DE28 /* BlackListViewController.swift in Sources */, 77AC35712B6CE8E200D046C2 /* ShareCardViewController.swift in Sources */, 778B8A842AF8ECE50034AFD4 /* HomeTabBarController.swift in Sources */, 77DFA9C52B4E8388005B8B13 /* MineDownloadViewController.swift in Sources */, diff --git a/IndieMusic/IndieMusic/Common/NavigationController.swift b/IndieMusic/IndieMusic/Common/NavigationController.swift index aab1039..6853e5d 100644 --- a/IndieMusic/IndieMusic/Common/NavigationController.swift +++ b/IndieMusic/IndieMusic/Common/NavigationController.swift @@ -101,44 +101,28 @@ class NavigationController: UINavigationController { extension NavigationController { override func pushViewController(_ viewController: UIViewController, animated: Bool) { - + guard let tabbar = self.tabBarController as? HomeTabBarController else { return } + if !children.isEmpty { -// viewController.hidesBottomBarWhenPushed = true -// if children.count > 1 { -// viewController.hidesBottomBarWhenPushed = false -// } - if let tabbar = self.tabBarController as? HomeTabBarController { - tabbar.showAllBar(false, animated: true) + + + if viewController is JournalDetailController { + let isShowPlayBar = AudioManager.sharedInstance.currentTrack.value != nil + tabbar.toggleBars(showTabBar: false, showPlayerBar: isShowPlayBar, animated: true) + } else if viewController is LoginViewController { + AudioManager.sharedInstance.pause() + tabbar.toggleBars(showTabBar: false, showPlayerBar: false, animated: true) + + } else if viewController is CommentViewController { + tabbar.toggleBars(showTabBar: false, showPlayerBar: false, animated: true) + + } else { + tabbar.toggleBars(showTabBar: false, showPlayerBar: true, animated: true) } -// viewController.hidesBottomBarWhenPushed = true -// let leftButton = UIButton.init() -// leftButton.setTitle("返回", for: .normal) -// leftButton.setImage(UIImage.init(named: "nav_back_btn"), for: .normal) -// leftButton.addTarget(self, action: #selector(backAction), for: .touchUpInside) -// -// let navLeftButton = UIBarButtonItem.init(customView: leftButton) -// navLeftButton.accessibilityLabel = "返回" -// viewController.navigationItem.leftBarButtonItem = navLeftButton - // -// let leftBarBtn = UIBarButtonItem(title: "返回", style: .plain, target: self,action: #selector(backAction)) -// leftBarBtn.image = UIImage(named: "nav_back_icon") -// self.navigationItem.leftBarButtonItem = leftBarBtn -// let button = UIButton.init() -// button.setImage(UIImage(named:"nav_back_btn"), for: .normal) -//// button.setTitle("返回1", for: .normal) -// button.addTarget(self, action: #selector(backAction), for: .touchUpInside) -// -// let leftBarBtn = UIBarButtonItem(customView: button) -// -// //用于消除左边空隙,要不然按钮顶不到最前面 -// let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, -// action: nil) -// spacer.width = -10 -// -// self.navigationItem.leftBarButtonItem = leftBarBtn + } super.pushViewController(viewController, animated: animated) } diff --git a/IndieMusic/IndieMusic/Configs/Configs.swift b/IndieMusic/IndieMusic/Configs/Configs.swift index 21e4bab..8049a21 100644 --- a/IndieMusic/IndieMusic/Configs/Configs.swift +++ b/IndieMusic/IndieMusic/Configs/Configs.swift @@ -62,7 +62,9 @@ struct BaseDimensions { static let bottomHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height > 20.0 ? 34.0 : 0 /// tab高度 static let tabBarHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height > 20.0 ? 83.0 : 49.0 - + /// 播放Bar高度 + static let playBarHeight: CGFloat = 66 + static let inset: CGFloat = 8 static let borderWidth: CGFloat = 1 } diff --git a/IndieMusic/IndieMusic/Managers/AudioManager.swift b/IndieMusic/IndieMusic/Managers/AudioManager.swift index 76d0421..40afaf7 100644 --- a/IndieMusic/IndieMusic/Managers/AudioManager.swift +++ b/IndieMusic/IndieMusic/Managers/AudioManager.swift @@ -221,6 +221,8 @@ class AudioManager { player.play() NotificationCenter.default.post(name: .notiPlayResume, object: nil) + } else if let track = playlist.value.first { + playTrack(track: track) } } diff --git a/IndieMusic/IndieMusic/Models/Followers.swift b/IndieMusic/IndieMusic/Models/Followers.swift index 7c3b4c0..61a9a64 100644 --- a/IndieMusic/IndieMusic/Models/Followers.swift +++ b/IndieMusic/IndieMusic/Models/Followers.swift @@ -8,13 +8,10 @@ import Foundation import RxDataSources -enum FollowersType: Codable { - case followers - case blackList -} + struct FollowersSection { - var followersType: FollowersType +// var followersType: FollowersType var items: [User] } diff --git a/IndieMusic/IndieMusic/Models/Message.swift b/IndieMusic/IndieMusic/Models/Message.swift index 0872937..333735a 100644 --- a/IndieMusic/IndieMusic/Models/Message.swift +++ b/IndieMusic/IndieMusic/Models/Message.swift @@ -18,6 +18,18 @@ enum CustomMessageType: Codable { case like(String) case follow(String) + + var content: String { + switch self { + case .comment(let string): + return string + case .like(let string): + return string + case .follow(let string): + return string + } + } + var description: String { switch self { case .comment: @@ -55,9 +67,9 @@ enum CustomMessageType: Codable { struct MessageList: Codable { - let comment: Message - let follow: Message - let thumbup: Message + let comment: Message? + let follow: Message? + let thumbup: Message? } diff --git a/IndieMusic/IndieMusic/Modules/Home/HomeTabBarController.swift b/IndieMusic/IndieMusic/Modules/Home/HomeTabBarController.swift index 4e0644a..f5eb156 100644 --- a/IndieMusic/IndieMusic/Modules/Home/HomeTabBarController.swift +++ b/IndieMusic/IndieMusic/Modules/Home/HomeTabBarController.swift @@ -133,11 +133,16 @@ class HomeTabBarController: UITabBarController, Navigatable { } playerTabBar.snp.makeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(customeTabBar.snp.top).offset(BaseDimensions.tabBarHeight) + make.left.right.equalTo(view) + make.bottom.equalTo(view) + if !self.customeTabBar.isHidden { + make.height.equalTo(BaseDimensions.bottomHeight + BaseDimensions.tabBarHeight + BaseDimensions.playBarHeight) + } else { + make.height.equalTo(BaseDimensions.bottomHeight + BaseDimensions.playBarHeight) + } } + } override func viewDidLayoutSubviews() { @@ -275,7 +280,6 @@ class HomeTabBarController: UITabBarController, Navigatable { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - } override func viewWillDisappear(_ animated: Bool) { @@ -283,184 +287,59 @@ class HomeTabBarController: UITabBarController, Navigatable { } - func showAllBar(_ isShowing: Bool, animated: Bool) { - + func toggleBars(showTabBar: Bool, showPlayerBar: Bool, animated: Bool) { if isAnimating { return } isAnimating = true - - - if isShowing { - customeTabBar.isHidden = false - - if AudioManager.sharedInstance.currentTrack != nil { - playerTabBar.isHidden = false - } - - + if showTabBar { + self.customeTabBar.isHidden = false customeTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) + make.left.right.equalTo(view) make.bottom.equalTo(view) make.height.equalTo(BaseDimensions.tabBarHeight) } - - playerTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(customeTabBar.snp.top) - } - } else { - customeTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(view).offset(self.tabBar.bounds.height) + make.left.right.equalTo(view) + make.bottom.equalTo(view).offset(BaseDimensions.tabBarHeight) make.height.equalTo(BaseDimensions.tabBarHeight) } - - playerTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(customeTabBar.snp.top).offset(BaseDimensions.tabBarHeight) - } - } - - var animationDuration = 0.3 - if animated == false { - animationDuration = 0 } - - UIView.animate(withDuration: animationDuration) { - if isShowing { - self.customeTabBar.alpha = 1 - self.playerTabBar.alpha = 1 - - } else { - self.customeTabBar.alpha = 0 - self.playerTabBar.alpha = 0 - - } - - self.view.layoutIfNeeded() - - } completion: { completed in - self.isTabBarShowing = isShowing - self.isPlayerBarShowing = isShowing - self.customeTabBar.isHidden = !isShowing - if AudioManager.sharedInstance.currentTrack != nil { - self.playerTabBar.isHidden = !isShowing - } - - - self.isAnimating = false - - } - } - - open func showTabBar(_ isShowing: Bool, animated: Bool) { - if isAnimating { return } - - isAnimating = true - - if isShowing { - customeTabBar.isHidden = false - - customeTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(view) - make.height.equalTo(BaseDimensions.tabBarHeight) - } - - } else { - - customeTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(view).offset(self.tabBar.bounds.height) - make.height.equalTo(BaseDimensions.tabBarHeight) - } - } - - var animationDuration = 0.3 - if animated == false { - animationDuration = 0 - } - - UIView.animate(withDuration: animationDuration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.25, - options: .curveEaseInOut, - animations: { - - if isShowing { - self.customeTabBar.alpha = 1 - } else { - self.customeTabBar.alpha = 0 - } - - self.view.layoutIfNeeded() - }) { (completed) in - self.isTabBarShowing = isShowing - self.customeTabBar.isHidden = !isShowing - self.isAnimating = false - } - } - - - open func showPlayerBar(_ isShowing: Bool, animated: Bool) { - if isAnimating { return } - - isAnimating = true - - if isShowing { - playerTabBar.isHidden = false + if showPlayerBar { playerTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) - make.bottom.equalTo(customeTabBar.snp.top) + make.left.right.equalTo(view) + make.bottom.equalTo(view) + if showTabBar { + make.height.equalTo( BaseDimensions.tabBarHeight + BaseDimensions.playBarHeight) + } else { + make.height.equalTo(BaseDimensions.bottomHeight + BaseDimensions.playBarHeight) + } } - } else { playerTabBar.snp.remakeConstraints { make in - make.left.equalTo(view) - make.right.equalTo(view) + make.left.right.equalTo(view) make.bottom.equalTo(customeTabBar.snp.top).offset(BaseDimensions.tabBarHeight) } - } - var animationDuration = 0.3 - if animated == false { - animationDuration = 0 - } - UIView.animate(withDuration: animationDuration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.25, - options: .curveEaseInOut, - animations: { - - if isShowing { - self.playerTabBar.alpha = 1 - } else { - self.playerTabBar.alpha = 0 - } - - self.view.layoutIfNeeded() - }) { (completed) in - self.isPlayerBarShowing = isShowing - self.playerTabBar.isHidden = !isShowing + + let animationDuration = animated ? 0.35 : 0 + + UIView.animate(withDuration: animationDuration, animations: { + + self.view.layoutIfNeeded() + }) { completed in + self.isTabBarShowing = showTabBar + self.isPlayerBarShowing = showPlayerBar + self.customeTabBar.isHidden = !showTabBar + self.playerTabBar.isHidden = !showPlayerBar self.isAnimating = false } } - + } diff --git a/IndieMusic/IndieMusic/Modules/Home/HomeViewController.swift b/IndieMusic/IndieMusic/Modules/Home/HomeViewController.swift index 541343e..f9bf325 100644 --- a/IndieMusic/IndieMusic/Modules/Home/HomeViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Home/HomeViewController.swift @@ -53,12 +53,19 @@ class HomeViewController: TableViewController, ScrollableNavBar { self.navigationItem.leftBarButtonItem = nil if let tabbar = self.tabBarController as? HomeTabBarController { - if tabbar.customeTabBar.isHidden == true && tabbar.playerTabBar.isHidden == true { - tabbar.showAllBar(true, animated: true) - } else if tabbar.playerTabBar.isHidden == true { - tabbar.playerTabBar.audioTrack = AudioManager.sharedInstance.currentTrack.value - tabbar.showPlayerBar(true, animated: true) - } +// if tabbar.customeTabBar.isHidden == true && tabbar.playerTabBar.isHidden == true { +// tabbar.showAllBar(true, animated: true) +// } else if tabbar.playerTabBar.isHidden == true { +// +// tabbar.showPlayerBar(true, animated: true) +// } + + let isShowPlayBar = AudioManager.sharedInstance.currentTrack.value != nil + tabbar.playerTabBar.audioTrack = AudioManager.sharedInstance.currentTrack.value + tabbar.toggleBars(showTabBar: true, showPlayerBar: isShowPlayBar, animated: true) + + + } if let navigationBar = self.navigationController?.navigationBar as? NavigationBar { diff --git a/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailController.swift b/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailController.swift index 70d3510..9b5b847 100644 --- a/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailController.swift +++ b/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailController.swift @@ -308,6 +308,15 @@ class JournalDetailController: TableViewController { }.disposed(by: rx.disposeBag) + AudioManager.sharedInstance.playlist.subscribe { audioTracks in + let isShow = audioTracks.element?.isEmpty == false + + if let tabbar = self.tabBarController as? HomeTabBarController { + tabbar.toggleBars(showTabBar: false, showPlayerBar: isShow, animated: true) + } + + }.disposed(by: rx.disposeBag) + } @@ -316,13 +325,19 @@ class JournalDetailController: TableViewController { super.viewDidLayoutSubviews() - commentToolView.snp.makeConstraints { make in + commentToolView.snp.remakeConstraints { make in make.left.equalTo(view) make.right.equalTo(view) - make.bottom.equalTo(view) + if AudioManager.sharedInstance.playlist.value.isEmpty == false { + make.bottom.equalTo(view).offset(-BaseDimensions.playBarHeight - 10) + } else { + make.bottom.equalTo(view) + } + make.height.equalTo(BaseDimensions.bottomHeight + 48) } + tableView.snp.remakeConstraints { make in make.left.equalTo(view) make.right.equalTo(view) diff --git a/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailView.swift b/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailView.swift index f51af85..b970ae0 100644 --- a/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailView.swift +++ b/IndieMusic/IndieMusic/Modules/JournalDetail/JournalDetailView.swift @@ -1064,7 +1064,7 @@ class JournalAudioCollectionViewCell: UICollectionViewCell { var buttonTapCallback: ((AudioTrack) -> ())? - + var audioTrack: AudioTrack? { didSet { @@ -1076,11 +1076,33 @@ class JournalAudioCollectionViewCell: UICollectionViewCell { coverView.kf.setImage(with: URL.init(string: audioTrack.pic ?? "")) - musicIndicator.state = AudioManager.sharedInstance.isPlaying() ? .playing : .paused + if AudioManager.sharedInstance.currentTrack.value?.id == audioTrack.id { + musicIndicator.state = AudioManager.sharedInstance.isPlaying() ? .playing : .paused + } else { + self.musicIndicator.state = .stopped + } + + AudioManager.sharedInstance.isPlayingState.subscribe { [weak self] isPlaying in + if AudioManager.sharedInstance.currentTrack.value?.id == audioTrack.id { + self?.musicIndicator.state = AudioManager.sharedInstance.isPlaying() ? .playing : .paused + } else { + self?.musicIndicator.state = .stopped + } + + }.disposed(by: disposeBag) } } + var disposeBag = DisposeBag() + + // 单元格重用时调用 + override func prepareForReuse() { + super.prepareForReuse() + disposeBag = DisposeBag() + } + + override init(frame: CGRect) { super.init(frame: frame) diff --git a/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift b/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift index 14e2ef9..f41cc9d 100644 --- a/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift @@ -12,67 +12,19 @@ import RxDataSources import FSPopoverView class MessageViewController: ViewController, UIScrollViewDelegate { - + var pageViewController: UIPageViewController! + + var pages = [UIViewController]() + let currentPageIndex = BehaviorRelay(value: 0) + + let messageTopView: MessageTopView = { let messageTopView = MessageTopView.init() return messageTopView }() - - var tableView: UITableView = { - let tableView = UITableView.init() - tableView.register(MessageCellView.self, forCellReuseIdentifier: "MessageCellView") - tableView.register(MessageActivitiesViewCell.self, forCellReuseIdentifier: "MessageActivitiesViewCell") - - return tableView - }() - - - private let menuView: PopoverListView = { - let menuView = PopoverListView.init(scrollDirection: .horizontal) - do { - let features: [PopoverMenu] = [.blockList, .delete] - let items: [FSPopoverListItem] = features.map { feature in - let item = FSPopoverListTextItem(scrollDirection: .horizontal) - item.title = feature.description - item.titleFont = UIFont.systemFont(ofSize: 12) - item.isSeparatorHidden = false - item.titleColor = .white - item.contentInset = .init(top: 9, left: 15, bottom: 9, right: 15) - item.selectedHandler = { item in - guard let item = item as? FSPopoverListTextItem else { - return - } - print(item.title ?? "") - } - item.updateLayout() - return item - } - items.last?.isSeparatorHidden = true - menuView.shadowOpacity = 0 - menuView.shadowRadius = 0 - menuView.shadowColor = .clear - menuView.items = items - menuView.cornerRadius = 3 - menuView.transitioningDelegate = nil - - menuView.arrowSize = CGSize.init(width: 18, height: 5) - menuView.backgroundColor = .primaryText() - } - - return menuView - }() - - - let headerRefreshTrigger = PublishSubject() - let footerRefreshTrigger = PublishSubject() - - let isHeaderLoading = BehaviorRelay(value: false) - let isFooterLoading = BehaviorRelay(value: false) - let messageType = BehaviorRelay.init(value: .message) - override func viewDidLoad() { super.viewDidLoad() @@ -81,63 +33,67 @@ class MessageViewController: ViewController, UIScrollViewDelegate { override func makeUI() { super.makeUI() + self.navigationItem.title = "消息列表" + messageTopView.segmentControl.titleBtnOnClick = { [weak self] (label, index) in if index == 0 { - self?.messageType.accept(.message) + self?.goToNextPage() } else { - self?.messageType.accept(.activities) + self?.goToPreviousPage() } + } - self.navigationItem.title = "消息列表" - tableView.rx.setDelegate(self).disposed(by: rx.disposeBag) + + guard let viewModel = viewModel as? MessageViewModel else { return } + + let privateMessageViewModel = PrivateMessageViewModel.init(provider: viewModel.provider) + + let privateMessage = PrivateMessageViewController.init(viewModel: privateMessageViewModel, navigator: self.navigator) + + let otherMessageViewModel = OtherMessageViewModel.init(provider: viewModel.provider) + + let otherMessage = OtherMessageViewController.init(viewModel: otherMessageViewModel, navigator: self.navigator) + + pages.append(privateMessage) + pages.append(otherMessage) + + setupPageViewController() view.addSubview(messageTopView) - view.addSubview(tableView) + view.backgroundColor = .white + + } override func bindViewModel() { super.bindViewModel() - -// self.segmentControl.currentSearchType = .single - + guard let viewModel = viewModel as? MessageViewModel else { return } - let refresh = Observable.of(Observable.just(()), headerRefreshTrigger).merge() - - let input = MessageViewModel.Input.init(viewWillAppear: rx.viewWillAppear, - headerRefresh: refresh, - footerRefresh: footerRefreshTrigger, - messageType: messageType, - modelSelected: tableView.rx.modelSelected(MessageSectionItem.self).asDriver()) + let input = MessageViewModel.Input.init(viewWillAppear: rx.viewWillAppear) let output = viewModel.transform(input: input) - let dataSource = MessageViewController.dataSource() - - - output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) - output.modelSelected.drive { [weak self] messageSectionItem in - - switch messageSectionItem { - case .customMessage(let customMessageType): - self?.navigateToScreen(customMessageType: customMessageType) - case .messageItem(let message): break - case .activitiesItem(let message): break - + pageViewController.rx.didFinishAnimating.subscribe { [weak self] (isFinished, previousViewControllers, completed) in + + if let privateMessage = self?.pageViewController.viewControllers?.first as? PrivateMessageViewController { + self?.messageTopView.segmentControl.selectedIndex(0, animated: true) + } else { + self?.messageTopView.segmentControl.selectedIndex(1, animated: true) } + }.disposed(by: rx.disposeBag) - } @@ -146,22 +102,19 @@ class MessageViewController: ViewController, UIScrollViewDelegate { messageTopView.snp.makeConstraints { make in - make.top.equalTo(view) make.left.equalTo(view) make.right.equalTo(view) - make.height.equalTo(49) + make.top.equalTo(view) } - - tableView.snp.makeConstraints { make in - make.top.equalTo(messageTopView.snp.bottom) + pageViewController.view.snp.remakeConstraints { make in make.left.equalTo(view) make.right.equalTo(view) + make.top.equalTo(messageTopView.snp.bottom) make.bottom.equalTo(view) } - + } - func navigateToScreen(customMessageType: CustomMessageType) { guard let viewModel = viewModel as? MessageViewModel else { return } @@ -179,7 +132,36 @@ class MessageViewController: ViewController, UIScrollViewDelegate { } + private func setupPageViewController() { + pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) + pageViewController.dataSource = self + + if let firstViewController = pages.first { + pageViewController.setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil) + } + + addChild(pageViewController) + view.addSubview(pageViewController.view) + pageViewController.didMove(toParent: self) + } + + func goToNextPage() { + guard let currentViewController = pageViewController?.viewControllers?.first, + let nextPage = pages.first else { + return + } + + pageViewController?.setViewControllers([nextPage], direction: .reverse, animated: true, completion: nil) + } + func goToPreviousPage() { + guard let currentViewController = pageViewController?.viewControllers?.first, + let previousPage = pages.last else { + return + } + + pageViewController?.setViewControllers([previousPage], direction: .forward, animated: true, completion: nil) + } } @@ -221,6 +203,47 @@ extension MessageViewController { } +extension MessageViewController: UIPageViewControllerDataSource { + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + guard let viewControllerIndex = pages.firstIndex(of: viewController) else { + return nil + } + + let previousIndex = viewControllerIndex - 1 + + guard previousIndex >= 0 else { + return nil + } + + guard pages.count > previousIndex else { + return nil + } + + + + return pages[previousIndex] + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + guard let viewControllerIndex = pages.firstIndex(of: viewController) else { + return nil + } + + let nextIndex = viewControllerIndex + 1 + let pagesCount = pages.count + + guard pagesCount != nextIndex else { + return nil + } + + guard pagesCount > nextIndex else { + return nil + } + + return pages[nextIndex] + } +} + class MessageTopView: UIView { @@ -282,13 +305,15 @@ class MessageTopView: UIView { segmentControl.snp.makeConstraints { make in make.width.equalTo(185) make.height.equalTo(44) - make.center.equalTo(self) + make.top.equalTo(self) + make.centerX.equalTo(self) } lineView.snp.makeConstraints { make in make.left.equalTo(self) make.right.equalTo(self) make.bottom.equalTo(self) + make.top.equalTo(segmentControl.snp.bottom) make.height.equalTo(6) } @@ -370,7 +395,13 @@ class MessageCellView: UITableViewCell { avatarView.image = UIImage.init(named: customMessageType.image) nameLabel.text = customMessageType.description - detailLabel.text = customMessageType.detail + + if customMessageType.content == "" { + detailLabel.text = "暂无\(customMessageType.description)" + } else { + detailLabel.text = customMessageType.detail + } + } } diff --git a/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift b/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift index 0b6be07..6a0f576 100644 --- a/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift @@ -14,20 +14,10 @@ class MessageViewModel: ViewModel, ViewModelType { struct Input { let viewWillAppear: ControlEvent - let headerRefresh: Observable - let footerRefresh: Observable - let messageType: BehaviorRelay - let modelSelected: Driver +// let messageType: BehaviorRelay } struct Output { - let messageItems: PublishRelay<[MessageSection]> - let activitiesItems: PublishRelay<[MessageSection]> - let items: BehaviorRelay<[MessageSection]> - - - let selection: PublishSubject - let modelSelected: Driver } @@ -86,71 +76,63 @@ class MessageViewModel: ViewModel, ViewModelType { // self.items.accept([MessageSection.activities(items: new)]) } // }).disposed(by: rx.disposeBag) - input.messageType.subscribe { [weak self] messageType in - guard let self = self, let messageType = messageType.element else { return } - self.messageType.accept(messageType) - - print("messageType \(messageType)") - self.page = 1 - switch messageType { - case .message: - - self.requestMessageList() - .subscribe { messageList in - var items = [messageList.comment, messageList.thumbup, messageList.follow] - - let comment = MessageSectionItem.customMessage(customMessageType: .comment(messageList.comment.sendUserNickName ?? "")) - let thumbup = MessageSectionItem.customMessage(customMessageType: .like(messageList.thumbup.sendUserNickName ?? "")) - let follow = MessageSectionItem.customMessage(customMessageType: .follow(messageList.follow.sendUserNickName ?? "")) - - - - self.messageItems.accept([MessageSection.message(items: [comment, thumbup, follow])]) - } onError: { error in - - }.disposed(by: self.rx.disposeBag) - - case .activities: break - } - - - - }.disposed(by: rx.disposeBag) +// input.messageType.subscribe { [weak self] messageType in +// guard let self = self, let messageType = messageType.element else { return } +// self.messageType.accept(messageType) +// +// print("messageType \(messageType)") +// self.page = 1 +// switch messageType { +// case .message: +// +// self.requestMessageList() +// .subscribe { messageList in +// var items = [messageList.comment, messageList.thumbup, messageList.follow] +// +// let comment = MessageSectionItem.customMessage(customMessageType: .comment(messageList.comment.sendUserNickName ?? "")) +// let thumbup = MessageSectionItem.customMessage(customMessageType: .like(messageList.thumbup.sendUserNickName ?? "")) +// let follow = MessageSectionItem.customMessage(customMessageType: .follow(messageList.follow.sendUserNickName ?? "")) +// +// +// +// self.messageItems.accept([MessageSection.message(items: [comment, thumbup, follow])]) +// } onError: { error in +// +// }.disposed(by: self.rx.disposeBag) +// +// case .activities: break +// } +// +// +// +// }.disposed(by: rx.disposeBag) - let cuttentItems = Observable.merge(messageItems.asObservable(), activitiesItems.asObservable()) - - cuttentItems.subscribe { [weak self] followersSections in - guard let self = self else { return } - - if self.messageType.value == .activities { - - } else { - self.items.accept(followersSections) - } - - }.disposed(by: rx.disposeBag) +// let cuttentItems = Observable.merge(messageItems.asObservable(), activitiesItems.asObservable()) +// +// cuttentItems.subscribe { [weak self] followersSections in +// guard let self = self else { return } +// +// if self.messageType.value == .activities { +// +// } else { +// self.items.accept(followersSections) +// } +// +// }.disposed(by: rx.disposeBag) - return Output.init(messageItems: messageItems, - activitiesItems: activitiesItems, - items: items, - selection: selection, - modelSelected: input.modelSelected) + return Output.init() } - func requestMessageList() -> Observable { - return self.provider.messageList() - .trackActivity(loading) - .trackError(error) - } + // func requestActivitiesList(page: Int, size: Int) -> Observable<[Message]> { // return self.provider.messageList(page: page, size: size) diff --git a/IndieMusic/IndieMusic/Modules/Message/OtherMessageViewController.swift b/IndieMusic/IndieMusic/Modules/Message/OtherMessageViewController.swift new file mode 100644 index 0000000..0c6f848 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Message/OtherMessageViewController.swift @@ -0,0 +1,147 @@ +// +// OtherMessageViewController.swift +// IndieMusic +// +// Created by WenLei on 2024/3/2. +// + +import UIKit +import RxSwift +import RxCocoa +import RxDataSources + +class OtherMessageViewModel: ViewModel, ViewModelType { + + struct Input { + let viewWillAppear: ControlEvent + let modelSelected: Driver + let footerRefresh: Observable + + } + + struct Output { + let items: BehaviorRelay<[MessageSection]> + let modelSelected: Driver + } + + let items = BehaviorRelay<[MessageSection]>.init(value: []) + + + func transform(input: Input) -> Output { + + input.viewWillAppear.subscribe { _ in + + + + }.disposed(by: rx.disposeBag) + + + + + return Output.init(items: items, + modelSelected: input.modelSelected) + + } + + + func requestMessageList() -> Observable { + return self.provider.messageList() + .trackActivity(loading) + .trackError(error) + } +} + + + + + +class OtherMessageViewController: TableViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + } + + + override func makeUI() { + super.makeUI() + + + tableView.register(MessageActivitiesViewCell.self, forCellReuseIdentifier: "MessageActivitiesViewCell") + + self.emptyDataSetDescription = "暂无活动消息!" + + } + + override func bindViewModel() { + super.bindViewModel() + + guard let viewModel = viewModel as? OtherMessageViewModel else { return } + + let input = OtherMessageViewModel.Input.init(viewWillAppear: rx.viewWillAppear, + modelSelected: tableView.rx.modelSelected(MessageSectionItem.self).asDriver(), + footerRefresh: footerRefreshTrigger) + + + + + let output = viewModel.transform(input: input) + let dataSource = PrivateMessageViewController.dataSource() + + output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) + + output.modelSelected.drive { [weak self] messageSectionItem in + +// switch messageSectionItem { +// case .customMessage(let customMessageType): +// self?.navigateToScreen(customMessageType: customMessageType) +// case .messageItem(let message): break +// case .activitiesItem(let message): break +// +// } + + }.disposed(by: rx.disposeBag) + + + + + } + +} + + +extension OtherMessageViewController { + + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( + configureCell: { dataSource, tableView, indexPath, item in + switch dataSource[indexPath] { + case .customMessage(let customMessageType): + let cell: MessageCellView = tableView.dequeueReusableCell(withIdentifier: "MessageCellView", for: indexPath) as! MessageCellView + + cell.customMessageType = customMessageType + + return cell + + + case .messageItem(let message): + let cell: MessageCellView = tableView.dequeueReusableCell(withIdentifier: "MessageCellView", for: indexPath) as! MessageCellView + + cell.message = message + + return cell + case .activitiesItem(let message): + let cell: MessageActivitiesViewCell = tableView.dequeueReusableCell(withIdentifier: "MessageActivitiesViewCell", for: indexPath) as! MessageActivitiesViewCell + + cell.message = message + return cell + + + } + } + ) + } + + +} + diff --git a/IndieMusic/IndieMusic/Modules/Message/PrivateMessageViewController.swift b/IndieMusic/IndieMusic/Modules/Message/PrivateMessageViewController.swift new file mode 100644 index 0000000..7cd0cba --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Message/PrivateMessageViewController.swift @@ -0,0 +1,216 @@ +// +// PrivateMessageViewController.swift +// IndieMusic +// +// Created by WenLei on 2024/3/2. +// + +import UIKit +import RxSwift +import RxCocoa +import RxDataSources +import FSPopoverView + + +class PrivateMessageViewModel: ViewModel, ViewModelType { + + struct Input { + let viewWillAppear: ControlEvent + let modelSelected: Driver + let footerRefresh: Observable + + } + + struct Output { + let items: BehaviorRelay<[MessageSection]> + let modelSelected: Driver + } + + let items = BehaviorRelay<[MessageSection]>.init(value: []) + + + func transform(input: Input) -> Output { + + input.viewWillAppear.subscribe { _ in + + self.requestMessageList().subscribe { messageList in + var items = [messageList.comment, messageList.thumbup, messageList.follow] + + let comment = MessageSectionItem.customMessage(customMessageType: .comment(messageList.comment?.sendUserNickName ?? "")) + let thumbup = MessageSectionItem.customMessage(customMessageType: .like(messageList.thumbup?.sendUserNickName ?? "")) + let follow = MessageSectionItem.customMessage(customMessageType: .follow(messageList.follow?.sendUserNickName ?? "")) + + + + self.items.accept([MessageSection.message(items: [comment, thumbup, follow])]) + + + + } onError: { error in + + }.disposed(by: self.rx.disposeBag) + + + }.disposed(by: rx.disposeBag) + + + + + return Output.init(items: items, + modelSelected: input.modelSelected) + + } + + + func requestMessageList() -> Observable { + return self.provider.messageList() + .trackActivity(loading) + .trackError(error) + } +} + + + + +class PrivateMessageViewController: TableViewController { + private let menuView: PopoverListView = { + let menuView = PopoverListView.init(scrollDirection: .horizontal) + do { + let features: [PopoverMenu] = [.blockList, .delete] + let items: [FSPopoverListItem] = features.map { feature in + let item = FSPopoverListTextItem(scrollDirection: .horizontal) + item.title = feature.description + item.titleFont = UIFont.systemFont(ofSize: 12) + item.isSeparatorHidden = false + item.titleColor = .white + item.contentInset = .init(top: 9, left: 15, bottom: 9, right: 15) + item.selectedHandler = { item in + guard let item = item as? FSPopoverListTextItem else { + return + } + print(item.title ?? "") + } + item.updateLayout() + return item + } + items.last?.isSeparatorHidden = true + menuView.shadowOpacity = 0 + menuView.shadowRadius = 0 + menuView.shadowColor = .clear + menuView.items = items + menuView.cornerRadius = 3 + menuView.transitioningDelegate = nil + + menuView.arrowSize = CGSize.init(width: 18, height: 5) + menuView.backgroundColor = .primaryText() + } + + return menuView + }() + + + + override func viewDidLoad() { + super.viewDidLoad() + + + } + + override func makeUI() { + super.makeUI() + + + tableView.register(MessageCellView.self, forCellReuseIdentifier: "MessageCellView") + + } + + override func bindViewModel() { + super.bindViewModel() + + guard let viewModel = viewModel as? PrivateMessageViewModel else { return } + + let input = PrivateMessageViewModel.Input.init(viewWillAppear: rx.viewWillAppear, + modelSelected: tableView.rx.modelSelected(MessageSectionItem.self).asDriver(), + footerRefresh: footerRefreshTrigger) + + + + + let output = viewModel.transform(input: input) + let dataSource = PrivateMessageViewController.dataSource() + + output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) + + output.modelSelected.drive { [weak self] messageSectionItem in + + switch messageSectionItem { + case .customMessage(let customMessageType): + self?.navigateToScreen(customMessageType: customMessageType) + case .messageItem(let message): break + case .activitiesItem(let message): break + + } + + }.disposed(by: rx.disposeBag) + + + + + } + + func navigateToScreen(customMessageType: CustomMessageType) { + guard let viewModel = viewModel as? PrivateMessageViewModel else { return } + + switch customMessageType { + case .comment: + let myCommentListViewModel = MyCommentListViewModel(provider: viewModel.provider) + self.navigator.show(segue: .myCommentList(viewModel: myCommentListViewModel), sender: self) + case .like: + let myLikeListViewModel = MyLikeListViewModel(provider: viewModel.provider) + self.navigator.show(segue: .myLikeList(viewModel: myLikeListViewModel), sender: self) + case .follow: + let followersViewModel = FollowersViewModel(provider: viewModel.provider) + self.navigator.show(segue: .followers(viewModel: followersViewModel), sender: self) + } + } + + + +} + +extension PrivateMessageViewController { + + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( + configureCell: { dataSource, tableView, indexPath, item in + switch dataSource[indexPath] { + case .customMessage(let customMessageType): + let cell: MessageCellView = tableView.dequeueReusableCell(withIdentifier: "MessageCellView", for: indexPath) as! MessageCellView + + cell.customMessageType = customMessageType + + + return cell + + + case .messageItem(let message): + let cell: MessageCellView = tableView.dequeueReusableCell(withIdentifier: "MessageCellView", for: indexPath) as! MessageCellView + + cell.message = message + + return cell + case .activitiesItem(let message): + let cell: MessageActivitiesViewCell = tableView.dequeueReusableCell(withIdentifier: "MessageActivitiesViewCell", for: indexPath) as! MessageActivitiesViewCell + + cell.message = message + return cell + + + } + } + ) + } + + +} + diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift b/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift index 19d82dc..72dfe2e 100644 --- a/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift @@ -42,7 +42,7 @@ class MineViewController: TableViewController { if let tabbar = self.tabBarController as? HomeTabBarController { - tabbar.showAllBar(true, animated: true) + tabbar.toggleBars(showTabBar: true, showPlayerBar: true, animated: true) } if AudioManager.sharedInstance.playlist.value.count > 0 { diff --git a/IndieMusic/IndieMusic/Modules/Personal/Followers/BlackListViewController.swift b/IndieMusic/IndieMusic/Modules/Personal/Followers/BlackListViewController.swift new file mode 100644 index 0000000..6d78b4c --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Personal/Followers/BlackListViewController.swift @@ -0,0 +1,218 @@ +// +// BlackListViewController.swift +// IndieMusic +// +// Created by WenLei on 2024/3/2. +// + +import UIKit +import RxSwift +import RxCocoa +import RxDataSources +import FSPopoverView + + +class BlackListViewModel: ViewModel, ViewModelType { + + struct Input { + let viewWillAppear: ControlEvent + let headerRefresh: Observable + let footerRefresh: Observable + let modelSelected: Driver + + } + + struct Output { + let items: BehaviorRelay<[FollowersSection]> + let modelSelected: Driver + } + + let items = BehaviorRelay<[FollowersSection]>.init(value: []) + + + func transform(input: Input) -> Output { + + input.viewWillAppear.subscribe { _ in + + + + }.disposed(by: rx.disposeBag) + + input.headerRefresh + .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in + guard let self = self else { return Observable.just([]) } + self.page = 1 + + return self.requestBlockList(page: page, size: 10) + .trackActivity(self.headerLoading) + + }) + .subscribe(onNext: { (items) in + self.items.accept([FollowersSection.init(items: items)]) + }).disposed(by: rx.disposeBag) + + input.footerRefresh + .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in + guard let self = self else { return Observable.just([]) } + self.page += 1 + + return self.requestBlockList(page: page, size: 10) + .trackActivity(self.headerLoading) + }) + .subscribe(onNext: { (items) in + + var arr = self.items.value.first?.items + arr?.append(contentsOf: items) + + self.items.accept([FollowersSection.init(items: arr ?? [])]) + }).disposed(by: rx.disposeBag) + + + + + + + + return Output.init(items: items, + modelSelected: input.modelSelected) + + } + + + func requestBlockList(page: Int, size: Int) -> Observable<[User]> { + return self.provider.blackList(page: page, size: size) + .trackActivity(loading) + .trackError(error) + } + + func requestLike(objectId: String, collectType: LikeType) -> Observable { + return self.provider.like(objectId: objectId, collectType: collectType.rawValue) + .trackActivity(loading) + .trackError(error) + + } + + + func requestCancelLike(objectId: String, collectType: LikeType) -> Observable { + return self.provider.cancelLike(objectId: objectId, collectType: collectType.rawValue) + .trackActivity(loading) + .trackError(error) + + } + +} + + + + +class BlackListViewController: TableViewController { + private let menuView: PopoverListView = { + let menuView = PopoverListView.init(scrollDirection: .horizontal) + do { + let features: [PopoverMenu] = [.blockList, .delete] + let items: [FSPopoverListItem] = features.map { feature in + let item = FSPopoverListTextItem(scrollDirection: .horizontal) + item.title = feature.description + item.titleFont = UIFont.systemFont(ofSize: 12) + item.isSeparatorHidden = false + item.titleColor = .white + item.contentInset = .init(top: 9, left: 15, bottom: 9, right: 15) + item.selectedHandler = { item in + guard let item = item as? FSPopoverListTextItem else { + return + } + print(item.title ?? "") + } + item.updateLayout() + return item + } + items.last?.isSeparatorHidden = true + menuView.shadowOpacity = 0 + menuView.shadowRadius = 0 + menuView.shadowColor = .clear + menuView.items = items + menuView.cornerRadius = 3 + menuView.transitioningDelegate = nil + + menuView.arrowSize = CGSize.init(width: 18, height: 5) + menuView.backgroundColor = .primaryText() + } + + return menuView + }() + + + + override func viewDidLoad() { + super.viewDidLoad() + + + } + + override func makeUI() { + super.makeUI() + + + tableView.register(FollowingViewCell.self, forCellReuseIdentifier: "FollowingViewCell") + emptyDataSetDescription = "你还没有把人拉黑!" + } + + override func bindViewModel() { + super.bindViewModel() + + guard let viewModel = viewModel as? BlackListViewModel else { return } + + let input = BlackListViewModel.Input.init(viewWillAppear: rx.viewWillAppear, + headerRefresh: headerRefreshTrigger, + footerRefresh: footerRefreshTrigger, modelSelected: tableView.rx.modelSelected(User.self).asDriver()) + + + + + let output = viewModel.transform(input: input) + let dataSource = BlackListViewController.dataSource { cell, user in + + } + + output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) + + output.modelSelected.drive { [weak self] messageSectionItem in + + + + }.disposed(by: rx.disposeBag) + + + + + } + + +} + +extension BlackListViewController { + //TODO + static func dataSource(_ buttonTapHandler: @escaping (UITableViewCell, User) -> Void) -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( + configureCell: { dataSource, tableView, indexPath, item in + let cell: FollowingViewCell = tableView.dequeueReusableCell(withIdentifier: "FollowingViewCell", for: indexPath) as! FollowingViewCell + + cell.user = item + + + cell.followingButton.setTitle("取消", for: .normal) + cell.followingButton.setTitle("添加", for: .selected) + if item.relation == .mutualFollowing { + cell.followingButton.isSelected = true + } + + cell.buttonTapCallback = {audioTrack in + buttonTapHandler(cell, audioTrack) + } + + return cell + } + ) + } +} + diff --git a/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewController.swift b/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewController.swift index 6f710eb..a555289 100644 --- a/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewController.swift @@ -11,29 +11,19 @@ import RxCocoa import RxDataSources class FollowersViewController: ViewController, UIScrollViewDelegate { - + var pageViewController: UIPageViewController! + + var pages = [UIViewController]() + let currentPageIndex = BehaviorRelay(value: 0) + + let followersTopView: FollowersTopView = { let followersTopView = FollowersTopView.init() return followersTopView }() - var tableView: UITableView = { - let tableView = UITableView.init() - tableView.register(FollowingViewCell.self, forCellReuseIdentifier: "FollowingViewCell") - - return tableView - }() - - - let followersType = BehaviorRelay.init(value: .followers) - - let headerRefreshTrigger = PublishSubject() - let footerRefreshTrigger = PublishSubject() - -// let isHeaderLoading = BehaviorRelay<(RefreshType, Bool)>.init(value: (.refresh, false)) -// let isFooterLoading = BehaviorRelay<(RefreshType, Bool)>.init(value: (.loadMore, false)) - + override func viewDidLoad() { super.viewDidLoad() @@ -42,21 +32,36 @@ class FollowersViewController: ViewController, UIScrollViewDelegate { override func makeUI() { super.makeUI() - + self.navigationItem.title = "粉丝" + followersTopView.segmentControl.titleBtnOnClick = { [weak self] (label, index) in if index == 0 { - self?.followersType.accept(.followers) + self?.goToNextPage() } else { - self?.followersType.accept(.blackList) + self?.goToPreviousPage() } - + } - self.navigationItem.title = "粉丝" - tableView.rx.setDelegate(self).disposed(by: rx.disposeBag) + + guard let viewModel = viewModel as? FollowersViewModel else { return } + + + let myFollowersViewModel = MyFollowersViewModel.init(provider: viewModel.provider) + + let myFollowers = MyFollowersViewController.init(viewModel: myFollowersViewModel, navigator: self.navigator) + + let blackListViewModel = BlackListViewModel.init(provider: viewModel.provider) + + let blackList = BlackListViewController.init(viewModel: blackListViewModel, navigator: self.navigator) + + pages.append(myFollowers) + pages.append(blackList) + + setupPageViewController() view.addSubview(followersTopView) - view.addSubview(tableView) + view.backgroundColor = .white } @@ -66,33 +71,24 @@ class FollowersViewController: ViewController, UIScrollViewDelegate { guard let viewModel = viewModel as? FollowersViewModel else { return } - let refresh = Observable.of(Observable.just(()), headerRefreshTrigger).merge() - let input = FollowersViewModel.Input.init(viewWillAppear: rx.viewWillAppear, - headerRefresh: refresh, - footerRefresh: footerRefreshTrigger, - followersType: self.followersType, - modelSelected: tableView.rx.modelSelected(User.self).asDriver()) + let input = FollowersViewModel.Input.init(viewWillAppear: rx.viewWillAppear) let output = viewModel.transform(input: input) - let dataSource = FollowersViewController.dataSource { [weak self] cell, user in - viewModel.itemSelected.onNext(user) - } - - output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) - - output.modelSelected.drive { [weak self] user in + pageViewController.rx.didFinishAnimating.subscribe { [weak self] (isFinished, previousViewControllers, completed) in + + if let myFollowers = self?.pageViewController.viewControllers?.first as? MyFollowersViewController { + self?.followersTopView.segmentControl.selectedIndex(0, animated: true) + } else { + self?.followersTopView.segmentControl.selectedIndex(1, animated: true) + } - let personalViewModel = PersonalViewModel.init(userID: user.id, provider: viewModel.provider) - self?.navigator.show(segue: .personal(viewModel: personalViewModel), sender: self) - }.disposed(by: rx.disposeBag) - } @@ -108,16 +104,45 @@ class FollowersViewController: ViewController, UIScrollViewDelegate { } - tableView.snp.makeConstraints { make in - make.top.equalTo(followersTopView.snp.bottom) + pageViewController.view.snp.remakeConstraints { make in make.left.equalTo(view) make.right.equalTo(view) + make.top.equalTo(followersTopView.snp.bottom) make.bottom.equalTo(view) } - } + private func setupPageViewController() { + pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) + pageViewController.dataSource = self + + if let firstViewController = pages.first { + pageViewController.setViewControllers([firstViewController], direction: .forward, animated: true, completion: nil) + } + + addChild(pageViewController) + view.addSubview(pageViewController.view) + pageViewController.didMove(toParent: self) + } + + func goToNextPage() { + guard let currentViewController = pageViewController?.viewControllers?.first, + let nextPage = pages.first else { + return + } + + pageViewController?.setViewControllers([nextPage], direction: .reverse, animated: true, completion: nil) + } + + func goToPreviousPage() { + guard let currentViewController = pageViewController?.viewControllers?.first, + let previousPage = pages.last else { + return + } + + pageViewController?.setViewControllers([previousPage], direction: .forward, animated: true, completion: nil) + } } @@ -131,18 +156,9 @@ extension FollowersViewController { cell.user = item - if dataSource[indexPath.row].followersType == .followers { - - cell.followingButton.setTitle("回关", for: .normal) - cell.followingButton.setTitle("互相关注", for: .selected) - if item.relation == .mutualFollowing { - cell.followingButton.isSelected = true - } - - } else { - cell.followingButton.setTitle("取消", for: .normal) - cell.followingButton.setTitle("添加", for: .selected) - } + cell.followingButton.setTitle("取消", for: .normal) + cell.followingButton.setTitle("添加", for: .selected) + cell.buttonTapCallback = {audioTrack in @@ -155,6 +171,49 @@ extension FollowersViewController { } } +extension FollowersViewController: UIPageViewControllerDataSource { + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + guard let viewControllerIndex = pages.firstIndex(of: viewController) else { + return nil + } + + let previousIndex = viewControllerIndex - 1 + + guard previousIndex >= 0 else { + return nil + } + + guard pages.count > previousIndex else { + return nil + } + + + + return pages[previousIndex] + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + guard let viewControllerIndex = pages.firstIndex(of: viewController) else { + return nil + } + + let nextIndex = viewControllerIndex + 1 + let pagesCount = pages.count + + guard pagesCount != nextIndex else { + return nil + } + + guard pagesCount > nextIndex else { + return nil + } + + return pages[nextIndex] + } +} + + + class FollowersTopView: UIView { lazy var segmentControl: ScrollSegmentView = { diff --git a/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewModel.swift b/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewModel.swift index 8b45905..61b0d5d 100644 --- a/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Personal/Followers/FollowersViewModel.swift @@ -13,30 +13,14 @@ class FollowersViewModel: ViewModel, ViewModelType { struct Input { let viewWillAppear: ControlEvent - let headerRefresh: Observable - let footerRefresh: Observable - let followersType: BehaviorRelay - let modelSelected: Driver } struct Output { - let followersItems: BehaviorRelay<[FollowersSection]> - let blocklistItems: BehaviorRelay<[FollowersSection]> - let items: BehaviorRelay<[FollowersSection]> - let modelSelected: Driver } - let followersItems = BehaviorRelay<[FollowersSection]>.init(value: []) - let blocklistItems = BehaviorRelay<[FollowersSection]>.init(value: []) - - let items = BehaviorRelay<[FollowersSection]>.init(value: []) - - let itemSelected = PublishSubject() - - let followersType = BehaviorRelay.init(value: .followers) func transform(input: Input) -> Output { @@ -44,29 +28,24 @@ class FollowersViewModel: ViewModel, ViewModelType { }.disposed(by: rx.disposeBag) - input.followersType.subscribe { [weak self] followersType in - guard let self = self else { return } - self.followersType.accept(followersType) - }.disposed(by: rx.disposeBag) - - input.headerRefresh.withLatestFrom(input.followersType) - .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in - guard let self = self else { return Observable.just([]) } - self.page = 1 - - if followersType == .followers { - return self.requestFollowersList(userId: UserDefaults.AccountInfo.string(forKey: .userID) ?? "", page: self.page, size: 10) - .trackActivity(self.headerLoading) - } else { - return self.requestBlockList(page: self.page, size: 10) - .trackActivity(self.headerLoading) - } - - }) - .subscribe(onNext: { (items) in - self.items.accept([FollowersSection.init(followersType: self.followersType.value, items: items)]) - }).disposed(by: rx.disposeBag) +// input.headerRefresh.withLatestFrom(input.followersType) +// .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in +// guard let self = self else { return Observable.just([]) } +// self.page = 1 +// +// if followersType == .followers { +// return self.requestFollowersList(userId: UserDefaults.AccountInfo.string(forKey: .userID) ?? "", page: self.page, size: 10) +// .trackActivity(self.headerLoading) +// } else { +// return self.requestBlockList(page: self.page, size: 10) +// .trackActivity(self.headerLoading) +// } +// +// }) +// .subscribe(onNext: { (items) in +// self.items.accept([FollowersSection.init(followersType: self.followersType.value, items: items)]) +// }).disposed(by: rx.disposeBag) // input.footerRefresh.withLatestFrom(input.followersType) // .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in @@ -202,19 +181,11 @@ class FollowersViewModel: ViewModel, ViewModelType { - return Output.init(followersItems: followersItems, - blocklistItems: blocklistItems, - items: self.items, - modelSelected: input.modelSelected) + return Output.init() } - func requestFollowersList(userId: String, page: Int, size: Int) -> Observable<[User]> { - return self.provider.followerList(userId: userId, page: page, size: size) - .trackActivity(loading) - .trackError(error) - } - + func requestBlockList(page: Int, size: Int) -> Observable<[User]> { return self.provider.blackList(page: page, size: size) diff --git a/IndieMusic/IndieMusic/Modules/Personal/Followers/MyFollowersViewController.swift b/IndieMusic/IndieMusic/Modules/Personal/Followers/MyFollowersViewController.swift new file mode 100644 index 0000000..26955e7 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Personal/Followers/MyFollowersViewController.swift @@ -0,0 +1,237 @@ +// +// MyFollowersViewController.swift +// IndieMusic +// +// Created by WenLei on 2024/3/2. +// + +import UIKit +import RxSwift +import RxCocoa +import RxDataSources +import FSPopoverView + + +class MyFollowersViewModel: ViewModel, ViewModelType { + + struct Input { + let viewWillAppear: ControlEvent + let headerRefresh: Observable + let footerRefresh: Observable + let modelSelected: Driver + + } + + struct Output { + let items: BehaviorRelay<[FollowersSection]> + let modelSelected: Driver + } + + let items = BehaviorRelay<[FollowersSection]>.init(value: []) + + + func transform(input: Input) -> Output { + + input.viewWillAppear.subscribe { _ in + self.requestFollowersList(page: self.page, size: 10) + .subscribe { users in + self.items.accept([FollowersSection.init(items: users)]) + + } onError: { error in + + }.disposed(by: self.rx.disposeBag) + + + + }.disposed(by: rx.disposeBag) + + input.headerRefresh + .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in + guard let self = self else { return Observable.just([]) } + self.page = 1 + + return self.requestFollowersList(page: page, size: 10) + .trackActivity(self.headerLoading) + + }) + .subscribe(onNext: { (items) in + self.items.accept([FollowersSection.init(items: items)]) + }).disposed(by: rx.disposeBag) + + input.footerRefresh + .flatMapLatest({ [weak self] (followersType) -> Observable<[User]> in + guard let self = self else { return Observable.just([]) } + self.page += 1 + + return self.requestFollowersList(page: page, size: 10) + .trackActivity(self.headerLoading) + }) + .subscribe(onNext: { (items) in + + var arr = self.items.value.first?.items + arr?.append(contentsOf: items) + + self.items.accept([FollowersSection.init(items: arr ?? [])]) + }).disposed(by: rx.disposeBag) + + + + + + + + return Output.init(items: items, + modelSelected: input.modelSelected) + + } + + + func requestFollowersList(page: Int, size: Int) -> Observable<[User]> { + return self.provider.followerList(userId: UserDefaults.AccountInfo.string(forKey: .userID) ?? "", page: page, size: size) + .trackActivity(loading) + .trackError(error) + } + + func requestLike(objectId: String, collectType: LikeType) -> Observable { + return self.provider.like(objectId: objectId, collectType: collectType.rawValue) + .trackActivity(loading) + .trackError(error) + + } + + + func requestCancelLike(objectId: String, collectType: LikeType) -> Observable { + return self.provider.cancelLike(objectId: objectId, collectType: collectType.rawValue) + .trackActivity(loading) + .trackError(error) + + } + +} + + + + +class MyFollowersViewController: TableViewController { + private let menuView: PopoverListView = { + let menuView = PopoverListView.init(scrollDirection: .horizontal) + do { + let features: [PopoverMenu] = [.blockList, .delete] + let items: [FSPopoverListItem] = features.map { feature in + let item = FSPopoverListTextItem(scrollDirection: .horizontal) + item.title = feature.description + item.titleFont = UIFont.systemFont(ofSize: 12) + item.isSeparatorHidden = false + item.titleColor = .white + item.contentInset = .init(top: 9, left: 15, bottom: 9, right: 15) + item.selectedHandler = { item in + guard let item = item as? FSPopoverListTextItem else { + return + } + print(item.title ?? "") + } + item.updateLayout() + return item + } + items.last?.isSeparatorHidden = true + menuView.shadowOpacity = 0 + menuView.shadowRadius = 0 + menuView.shadowColor = .clear + menuView.items = items + menuView.cornerRadius = 3 + menuView.transitioningDelegate = nil + + menuView.arrowSize = CGSize.init(width: 18, height: 5) + menuView.backgroundColor = .primaryText() + } + + return menuView + }() + + + + override func viewDidLoad() { + super.viewDidLoad() + + + } + + override func makeUI() { + super.makeUI() + + + tableView.register(FollowingViewCell.self, forCellReuseIdentifier: "FollowingViewCell") + emptyDataSetDescription = "还没有人关注你噢!" + + } + + override func bindViewModel() { + super.bindViewModel() + + guard let viewModel = viewModel as? MyFollowersViewModel else { return } + + let input = MyFollowersViewModel.Input.init(viewWillAppear: rx.viewWillAppear, + headerRefresh: headerRefreshTrigger, + footerRefresh: footerRefreshTrigger, modelSelected: tableView.rx.modelSelected(User.self).asDriver()) + + + + let output = viewModel.transform(input: input) + let dataSource = MyFollowersViewController.dataSource { cell, user in + + } + + output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag) + + output.modelSelected.drive { [weak self] user in + + let personalViewModel = PersonalViewModel.init(userID: user.id, provider: viewModel.provider) + self?.navigator.show(segue: .personal(viewModel: personalViewModel), sender: self) + + + }.disposed(by: rx.disposeBag) + + + + + } + + +} + +extension MyFollowersViewController { + //TODO + static func dataSource(_ buttonTapHandler: @escaping (UITableViewCell, User) -> Void) -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( + configureCell: { dataSource, tableView, indexPath, item in + let cell: FollowingViewCell = tableView.dequeueReusableCell(withIdentifier: "FollowingViewCell", for: indexPath) as! FollowingViewCell + + cell.user = item + + + cell.followingButton.setTitle("回关", for: .normal) + cell.followingButton.setTitle("互相关注", for: .selected) + if item.relation == .mutualFollowing { + cell.followingButton.isSelected = true + } + + +// if dataSource[indexPath.row].followersType == .followers { +// +// +// } else { +// cell.followingButton.setTitle("取消", for: .normal) +// cell.followingButton.setTitle("添加", for: .selected) +// } + + + cell.buttonTapCallback = {audioTrack in + buttonTapHandler(cell, audioTrack) + } + + return cell + } + ) + } +} + diff --git a/IndieMusic/IndieMusic/Modules/Player/PlayerTabBar.swift b/IndieMusic/IndieMusic/Modules/Player/PlayerTabBar.swift index 25f8451..a32e1cb 100644 --- a/IndieMusic/IndieMusic/Modules/Player/PlayerTabBar.swift +++ b/IndieMusic/IndieMusic/Modules/Player/PlayerTabBar.swift @@ -10,9 +10,9 @@ import MarqueeLabel class PlayerTabBar: UIControl { var blurEffectView: BlurEffectView = { - let blurEffectView = BlurEffectView.init() - blurEffectView.imageView.isHidden = true - + let blurEffectView = BlurEffectView.init(style: .systemMaterial, frame: .zero) +// blurEffectView.isHidden = true + blurEffectView.backgroundColor = .white return blurEffectView }() @@ -27,7 +27,6 @@ class PlayerTabBar: UIControl { private var containerView: UIView = { var containerView = UIView.init() - containerView.backgroundColor = .white return containerView }() @@ -85,10 +84,6 @@ class PlayerTabBar: UIControl { super.init(frame: frame) makeUI() - -// titleLabel.text = "标题" -// artistLabel.text = "作者" -// progressView.progress = 0 } required init?(coder: NSCoder) { @@ -97,8 +92,9 @@ class PlayerTabBar: UIControl { func makeUI() { +// backgroundColor = .white - + addSubview(blurEffectView) containerView.addSubview(titleLabel) containerView.addSubview(artistLabel) @@ -113,17 +109,24 @@ class PlayerTabBar: UIControl { override func layoutSubviews() { super.layoutSubviews() - coverView.snp.remakeConstraints { make in + blurEffectView.snp.makeConstraints { make in + + make.left.equalTo(self) + make.right.equalTo(self) + make.bottom.equalTo(self) + make.top.equalTo(self).offset(12) + } + + coverView.snp.makeConstraints { make in make.left.equalTo(self).offset(30) make.top.equalTo(self).offset(0) make.size.equalTo(CGSize.init(width: 52, height: 52)) - make.bottom.equalTo(self).offset(-14) } containerView.snp.makeConstraints { make in make.left.equalTo(self) make.right.equalTo(self) - make.bottom.equalTo(self) + make.top.equalTo(self).offset(12) make.height.equalTo(54) } @@ -154,7 +157,7 @@ class PlayerTabBar: UIControl { progressView.snp.makeConstraints { make in make.left.equalTo(self).offset(30) make.right.equalTo(self).offset(-30) - make.bottom.equalTo(self) + make.top.equalTo(containerView.snp.bottom) make.height.equalTo(2) } diff --git a/IndieMusic/IndieMusic/Modules/Player/PlayerView.swift b/IndieMusic/IndieMusic/Modules/Player/PlayerView.swift index 587a213..e05d71f 100644 --- a/IndieMusic/IndieMusic/Modules/Player/PlayerView.swift +++ b/IndieMusic/IndieMusic/Modules/Player/PlayerView.swift @@ -101,8 +101,8 @@ class PlayerControlView: UIView { var playButton: UIButton = { let playButton = UIButton.init() - playButton.setImage(UIImage.init(named: "play_pause_btn"), for: .normal) - playButton.setImage(UIImage.init(named: "play_play_btn"), for: .selected) + playButton.setImage(UIImage.init(named: "play_pause_btn"), for: .selected) + playButton.setImage(UIImage.init(named: "play_play_btn"), for: .normal) return playButton }() diff --git a/IndieMusic/IndieMusic/Modules/Player/PlayerViewController.swift b/IndieMusic/IndieMusic/Modules/Player/PlayerViewController.swift index fcdc1c8..ea39984 100644 --- a/IndieMusic/IndieMusic/Modules/Player/PlayerViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Player/PlayerViewController.swift @@ -129,14 +129,18 @@ class PlayerViewController: ViewController { - viewModel.isPlaying - .bind(to: self.playerControlView.playButton.rx.isSelected) - .disposed(by: rx.disposeBag) +// viewModel.isPlaying +// .bind(to: self.playerControlView.playButton.rx.isSelected) +// .disposed(by: rx.disposeBag) +// +// viewModel.isPlaying.subscribe { [weak self] isPlaying in +// self?.playerControlView.playButton.isSelected = isPlaying +// +// } .disposed(by: rx.disposeBag) +// + + AudioManager.sharedInstance.isPlayingState.bind(to: self.playerControlView.playButton.rx.isSelected).disposed(by: rx.disposeBag) - viewModel.isPlaying.subscribe { [weak self] isPlaying in - self?.playerControlView.playButton.isSelected = isPlaying - - } .disposed(by: rx.disposeBag) output.currentAudioTrack.subscribe { [weak self] audioTrack in @@ -162,25 +166,6 @@ class PlayerViewController: ViewController { }.disposed(by: rx.disposeBag) -// output.progress.subscribe { [weak self] progress in -// guard let self = self else { return } -// -// if !self.playerScrollView.playerInfoView.playerSlider.isDrop { -// self.playerScrollView.playerInfoView.playerSlider.slider.value = progress -// } -// }.disposed(by: rx.disposeBag) -// -// output.duration.subscribe { [weak self] duration in -// guard let self = self else { return } -// -// self.playerScrollView.playerInfoView.playerSlider.totalSec = duration -// }.disposed(by: rx.disposeBag) -// -// output.time.subscribe { [weak self] time in -// guard let self = self else { return } -// -// self.playerScrollView.playerInfoView.playerSlider.updateTimeLabel(currentTime: time) -// }.disposed(by: rx.disposeBag) output.isPlaying.bind(to: self.playerControlView.playButton.rx.isSelected).disposed(by: rx.disposeBag) diff --git a/IndieMusic/IndieMusic/Modules/Player/PlayerViewModel.swift b/IndieMusic/IndieMusic/Modules/Player/PlayerViewModel.swift index 1f61dd2..b0743b6 100644 --- a/IndieMusic/IndieMusic/Modules/Player/PlayerViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Player/PlayerViewModel.swift @@ -188,19 +188,6 @@ class PlayerViewModel: ViewModel, ViewModelType { }.disposed(by: rx.disposeBag) - input.notiPlayPause.subscribe { [weak self] noti in - guard let self = self else { return } - - self.isPlaying.accept(true) - }.disposed(by: rx.disposeBag) - - input.notiPlayResume.subscribe { [weak self] noti in - guard let self = self else { return } - - self.isPlaying.accept(false) - }.disposed(by: rx.disposeBag) - - return Output.init(items: items, shuffle: shuffle, diff --git a/IndieMusic/IndieMusic/Modules/Search/SearchResults/SongResultsViewController.swift b/IndieMusic/IndieMusic/Modules/Search/SearchResults/SongResultsViewController.swift index cf8f34c..c3308de 100644 --- a/IndieMusic/IndieMusic/Modules/Search/SearchResults/SongResultsViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Search/SearchResults/SongResultsViewController.swift @@ -185,7 +185,6 @@ class SongResultsViewController: CollectionViewController { return singleColumnSection } - let collectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: layout) collectionView.register(JournalViewCell.self, forCellWithReuseIdentifier: "JournalViewCell") collectionView.register(JournalAudioCollectionViewCell.self, forCellWithReuseIdentifier: "JournalAudioCollectionViewCell") collectionView.collectionViewLayout = layout diff --git a/IndieMusic/IndieMusic/Modules/Search/SearchViewController.swift b/IndieMusic/IndieMusic/Modules/Search/SearchViewController.swift index 11c1587..9a3333a 100644 --- a/IndieMusic/IndieMusic/Modules/Search/SearchViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Search/SearchViewController.swift @@ -53,7 +53,7 @@ class SearchViewController: ViewController, UIScrollViewDelegate { if let tabbar = self.tabBarController as? HomeTabBarController { - tabbar.showAllBar(true, animated: true) + tabbar.toggleBars(showTabBar: true, showPlayerBar: true, animated: true) } self.navigationController?.setNavigationBarHidden(true, animated: false)