Sharing, more, journal details module building

dev
wenlei 1 year ago
parent 483c8d36c2
commit 53fde354c9

@ -137,6 +137,7 @@
77FA0B5C2B147EE800404C5E /* CommentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FA0B5B2B147EE800404C5E /* CommentView.swift */; };
77FAF7622B07434A00FC2CA1 /* AudioMoreActionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FAF7612B07434A00FC2CA1 /* AudioMoreActionController.swift */; };
77FAF7642B075FEB00FC2CA1 /* JournalDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FAF7632B075FEB00FC2CA1 /* JournalDetailViewModel.swift */; };
77FB7A702B48074600B64030 /* MusicStyleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */; };
B570F70B7040469E9D729E7E /* Pods_IndieMusic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA421D41748C113CCE36A32 /* Pods_IndieMusic.framework */; };
/* End PBXBuildFile section */
@ -296,6 +297,7 @@
77FA0B5B2B147EE800404C5E /* CommentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentView.swift; sourceTree = "<group>"; tabWidth = 14; };
77FAF7612B07434A00FC2CA1 /* AudioMoreActionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMoreActionController.swift; sourceTree = "<group>"; };
77FAF7632B075FEB00FC2CA1 /* JournalDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JournalDetailViewModel.swift; sourceTree = "<group>"; };
77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicStyleViewModel.swift; sourceTree = "<group>"; };
A90C808FB1B74BB851FB67CB /* Pods-IndieMusic-IndieMusicUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IndieMusic-IndieMusicUITests.debug.xcconfig"; path = "Target Support Files/Pods-IndieMusic-IndieMusicUITests/Pods-IndieMusic-IndieMusicUITests.debug.xcconfig"; sourceTree = "<group>"; };
B4D1DC4EEC82560A8FAECF4A /* Pods-IndieMusic-IndieMusicUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IndieMusic-IndieMusicUITests.release.xcconfig"; path = "Target Support Files/Pods-IndieMusic-IndieMusicUITests/Pods-IndieMusic-IndieMusicUITests.release.xcconfig"; sourceTree = "<group>"; };
C8F1B981837A2D1AAE58D709 /* Pods-IndieMusic.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IndieMusic.release.xcconfig"; path = "Target Support Files/Pods-IndieMusic/Pods-IndieMusic.release.xcconfig"; sourceTree = "<group>"; };
@ -657,6 +659,7 @@
778B8A7D2AF8ECE50034AFD4 /* SearchViewController.swift */,
778B8A7E2AF8ECE50034AFD4 /* SearchViewModel.swift */,
7751D3732B43C9FA00F1F2BD /* MusicStyleViewController.swift */,
77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */,
7751D3772B43EA1200F1F2BD /* SearchResultsController.swift */,
);
path = Search;
@ -983,6 +986,7 @@
774A18092B06120000F56DF1 /* Home.swift in Sources */,
778B8ABF2AF8ED280034AFD4 /* NavigationController.swift in Sources */,
774399AA2AFE3170006F8EEA /* PaddingLabel.swift in Sources */,
77FB7A702B48074600B64030 /* MusicStyleViewModel.swift in Sources */,
7751D3502B42ABBF00F1F2BD /* SettingViewController.swift in Sources */,
77FA0B4E2B0EF8C700404C5E /* PhoneCodeViewModel.swift in Sources */,
778B8A822AF8ECE50034AFD4 /* HomeViewModel.swift in Sources */,

@ -23,6 +23,10 @@ class Navigator {
case search(viewModel: HomeTabBarViewModel)
case journalDetail(viewModel: JournalDetailViewModel)
case filter(viewModel: FilterViewModel)
case audioMore(viewModel: AudioMoreActionViewModel)
case share(viewModel: ShareActionViewModel)
case musicStyle(viewModel: MusicStyleViewModel)
case test
case safari(URL)
@ -63,6 +67,13 @@ class Navigator {
return JournalDetailController.init(viewModel: viewModel, navigator: self)
case .filter(viewModel: let viewModel):
return FilterViewController.init(viewModel: viewModel, navigator: self)
case .audioMore(viewModel: let viewModel):
return AudioMoreActionController.init(viewModel: viewModel, navigator: self)
case .share(viewModel: let viewModel):
return ShareActionController.init(viewModel: viewModel, navigator: self)
case .musicStyle(viewModel: let viewModel):
return MusicStyleViewController.init(viewModel: viewModel, navigator: self)
case .test:
let test = UIViewController.init()

@ -10,6 +10,8 @@ import UIKit
enum PresentationViewType {
case tips(Bool)
case filter
case audioMore
case share
}
class PresentationController: UIPresentationController {
@ -57,6 +59,13 @@ class CardPresentationController: PresentationController {
case .filter:
return containerView.bounds
.inset(by: UIEdgeInsets(top: containerView.bounds.height - 474 - BaseDimensions.bottomHeight, left: 0, bottom: 0, right: 0))
case .audioMore:
return containerView.bounds
.inset(by: UIEdgeInsets(top: containerView.bounds.height - 323 - BaseDimensions.bottomHeight, left: 0, bottom: 0, right: 0))
case .share:
return containerView.bounds
.inset(by: UIEdgeInsets(top: containerView.bounds.height - 181 - BaseDimensions.bottomHeight, left: 0, bottom: 0, right: 0))
case .tips:
return containerView.bounds
}
@ -90,6 +99,19 @@ class CardPresentationController: PresentationController {
self?.containerView?.backgroundColor = UIColor.black.withAlphaComponent(0.8)
}, completion: nil)
case .audioMore:
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.containerView?.backgroundColor = UIColor.black.withAlphaComponent(0.8)
}, completion: nil)
case .share:
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.containerView?.backgroundColor = UIColor.black.withAlphaComponent(0.8)
}, completion: nil)
case .tips(let isTapDismiss):
coordinator.animate(alongsideTransition: { [weak self] _ in

@ -8,20 +8,26 @@
import Foundation
import RxDataSources
//struct Journal: Codable {
// let audio: String?
// let cover: String?
// let title: String?
// let artist: String?
//}
struct JournalDetail: Codable {
let audio: String?
let cover: String?
let title: String?
let artist: String?
let number: String?
let tags: [String]?
let date: Int?
let content: String?
let isExpand: Bool?
}
struct JournalSection {
var items: [AudioTrack]
var isDownloaded: Bool
var isLike: Bool
let journalDetail: JournalDetail
}
extension JournalSection: SectionModelType {

@ -17,6 +17,10 @@ struct MusicStyle: Codable {
struct MusicStyleSection {
var items: [MusicStyle]
var header: String
var headerSub: String
var content: String
var isExpand: Bool
}

@ -296,7 +296,8 @@ class HomeSectionView: UIView {
}()
var theFMButtonClosures: (()->())?
var filterButtonClosures: (()->())?
override init(frame: CGRect) {
super.init(frame: frame)
@ -311,11 +312,14 @@ class HomeSectionView: UIView {
}
func makeUI() {
backgroundColor = .white
addSubview(titleLabel)
addSubview(theFMButton)
addSubview(filterButton)
theFMButton.addTarget(self, action: #selector(theFMButtonClick), for: .touchUpInside)
filterButton.addTarget(self, action: #selector(filterButtonClick), for: .touchUpInside)
}
@ -327,6 +331,14 @@ class HomeSectionView: UIView {
}
}
@objc func filterButtonClick() {
if let filterButtonClosures = self.filterButtonClosures {
filterButtonClosures()
self.filterButton.setNeedsLayout()
self.filterButton.layoutIfNeeded()
}
}
override func layoutSubviews() {
super.layoutSubviews()
@ -422,3 +434,64 @@ class HomeFilterButton: UIControl {
}
}
class NoLoginBottomView: UIView {
var loginButton: UIButton = {
let loginButton = UIButton.init()
loginButton.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
loginButton.layer.cornerRadius = 16
loginButton.layer.masksToBounds = true
loginButton.layer.borderColor = UIColor.tertiaryText().cgColor
loginButton.layer.borderWidth = 1
loginButton.setTitleColor(UIColor.primaryText(), for: .normal)
loginButton.setTitle("登录看更多", for: .normal)
return loginButton
}()
var gradientLayer: CAGradientLayer = {
let gradientLayer = CAGradientLayer.init()
gradientLayer.colors = [UIColor.init(hex: 0xFFFFFF, alpha: 0).cgColor,
UIColor.init(hex: 0xFFFFFF, alpha: 0.8).cgColor]
gradientLayer.locations = [0.0, 0.9]
gradientLayer.startPoint = CGPoint.init(x: 0 , y: 0)
gradientLayer.endPoint = CGPoint.init(x: 0, y: 1)
return gradientLayer
}()
override init(frame: CGRect) {
super.init(frame: frame)
makeUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func makeUI() {
addSubview(loginButton)
layer.insertSublayer(gradientLayer, at: 0)
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = self.bounds
loginButton.snp.makeConstraints { make in
make.centerX.equalTo(self)
make.top.equalTo(self).offset(15)
make.size.equalTo(CGSize.init(width: 118, height: 32))
}
}
}

@ -27,6 +27,12 @@ class HomeViewController: TableViewController {
var bannerArray = [String]()
let noLoginBottomView: NoLoginBottomView = {
let noLoginBottomView = NoLoginBottomView.init()
// noLoginBottomView.backgroundColor = .systemBlue
return noLoginBottomView
}()
override func viewDidLoad() {
super.viewDidLoad()
@ -43,6 +49,9 @@ class HomeViewController: TableViewController {
//
// self.navigationController?.pushViewController(vc, animated: true)
if let tabbar = self.tabBarController as? HomeTabBarController {
tabbar.showTabBar(true, animated: true)
}
guard let viewModel = viewModel as? HomeViewModel else { return }
@ -68,7 +77,7 @@ class HomeViewController: TableViewController {
tableView.register(HomeViewCell.self, forCellReuseIdentifier: "HomeViewCell")
view.addSubview(noLoginBottomView)
}
@ -91,23 +100,20 @@ class HomeViewController: TableViewController {
switch sectionItem {
default:
default:
let filterViewModel = FilterViewModel.init(provider: viewModel.provider)
let filter = FilterViewController.init(viewModel: filterViewModel, navigator: self.navigator)
// self.present(filter, animated: true)
self.navigator.show(segue: .filter(viewModel: filterViewModel), sender: self, transition: .navigationPresent(type: .filter))
// self.navigator.show(segue: .test, sender: self, transition: .modal)
// let journalDetailViewModel = JournalDetailViewModel.init(provider: viewModel.provider)
// self.navigator.show(segue: .journalDetail(viewModel: journalDetailViewModel), sender: self)
let journalDetailViewModel = JournalDetailViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .journalDetail(viewModel: journalDetailViewModel), sender: self)
}
}.disposed(by: rx.disposeBag)
}
@ -115,6 +121,14 @@ class HomeViewController: TableViewController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
noLoginBottomView.snp.makeConstraints { make in
make.bottom.equalTo(view).offset( -BaseDimensions.tabBarHeight)
make.left.equalTo(view)
make.right.equalTo(view)
make.height.equalTo(86)
}
}
@ -180,7 +194,18 @@ extension HomeViewController {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = HomeSectionView.init()
header.theFMButtonClosures = {
}
header.filterButtonClosures = {[weak self] in
header.filterButton.isFiltered.toggle()
guard let viewModel = self?.viewModel as? HomeViewModel,
let navigator = self?.navigator else { return }
let filterViewModel = FilterViewModel.init(provider: viewModel.provider)
let filter = FilterViewController.init(viewModel: filterViewModel, navigator: navigator)
// self.present(filter, animated: true)
navigator.show(segue: .filter(viewModel: filterViewModel), sender: self, transition: .navigationPresent(type: .filter))
}
return header

@ -14,6 +14,7 @@ class HomeViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
@ -21,6 +22,7 @@ class HomeViewModel: ViewModel, ViewModelType {
let items: BehaviorRelay<[HomeSectionModel]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<HomeSectionItem>
// let filterTrigger: Driver<Filter>
}

@ -43,15 +43,21 @@ class SongViewCell: UITableViewCell {
return detailLabel
}()
lazy var menuButtin: UIButton = {
lazy var moreButtin: UIButton = {
let menuButtin = UIButton.init()
menuButtin.setImage(UIImage.init(named: ""), for: .normal)
menuButtin.setImage(UIImage.init(named: "audio_more_btn"), for: .normal)
menuButtin.setContentHuggingPriority(.required, for: .horizontal)
menuButtin.setContentCompressionResistancePriority(.required, for: .horizontal)
menuButtin.addTarget(self, action: #selector(menuButtinClick), for: .touchUpInside)
return menuButtin
}()
var buttonTapCallback: ((AudioTrack) -> ())?
override var isEditing: Bool {
didSet {
selectButton.isHidden = !isEditing
@ -85,9 +91,9 @@ class SongViewCell: UITableViewCell {
}
var audio: AudioTrack? {
var audioTrack: AudioTrack? {
didSet {
titleLabel.text = audio?.name
titleLabel.text = audioTrack?.name
detailLabel.text = "321"
@ -96,6 +102,7 @@ class SongViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
makeUI()
}
@ -109,7 +116,7 @@ class SongViewCell: UITableViewCell {
contentView.addSubview(coverView)
contentView.addSubview(titleLabel)
contentView.addSubview(detailLabel)
contentView.addSubview(menuButtin)
contentView.addSubview(moreButtin)
@ -122,7 +129,7 @@ class SongViewCell: UITableViewCell {
make.bottom.equalTo(contentView).offset(-23)
}
menuButtin.snp.makeConstraints { make in
moreButtin.snp.makeConstraints { make in
make.right.equalTo(contentView).offset(-18)
make.centerY.equalTo(coverView)
}
@ -130,17 +137,22 @@ class SongViewCell: UITableViewCell {
titleLabel.snp.makeConstraints { make in
make.left.equalTo(coverView.snp.right).offset(15)
make.top.equalTo(coverView).offset(10)
make.right.equalTo(menuButtin.snp.left).offset(-10)
make.right.equalTo(moreButtin.snp.left).offset(-10)
}
detailLabel.snp.makeConstraints { make in
make.left.equalTo(coverView.snp.right).offset(15)
make.top.equalTo(titleLabel.snp.bottom).offset(10)
make.right.equalTo(menuButtin.snp.left).offset(-6)
make.right.equalTo(moreButtin.snp.left).offset(-6)
}
}
@objc func menuButtinClick() {
if let buttonTapCallback = self.buttonTapCallback,
let audioTrack = self.audioTrack {
buttonTapCallback(audioTrack)
}
}
}

@ -13,7 +13,7 @@ import RxDataSources
class AudioMoreActionController: ViewController, UIScrollViewDelegate {
var audioMoreActionView: AudioMoreActionView = {
let audioMoreActionView = AudioMoreActionView.init(frame: CGRect.init(x: 0, y: 0, width: BaseDimensions.screenWidth, height: 95))
audioMoreActionView.backgroundColor = .red
// audioMoreActionView.backgroundColor = .red
audioMoreActionView.titleLabel.text = "123"
audioMoreActionView.detailLabel.text = "432"
@ -31,7 +31,7 @@ class AudioMoreActionController: ViewController, UIScrollViewDelegate {
var audioMoreActionBottomView: AudioMoreActionBottomView = {
let audioMoreActionBottomView = AudioMoreActionBottomView.init()
audioMoreActionBottomView.backgroundColor = .blue
// audioMoreActionBottomView.backgroundColor = .blue
return audioMoreActionBottomView
}()
@ -47,7 +47,8 @@ class AudioMoreActionController: ViewController, UIScrollViewDelegate {
super.makeUI()
tableView.rx.setDelegate(self).disposed(by: rx.disposeBag)
tableView.separatorColor = .clear
view.backgroundColor = .white
view.addSubview(audioMoreActionView)
view.addSubview(tableView)
@ -63,7 +64,7 @@ class AudioMoreActionController: ViewController, UIScrollViewDelegate {
guard let viewModel = viewModel as? AudioMoreActionViewModel else { return }
let input = AudioMoreActionViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
selection: tableView.rx.itemSelected.asDriver(), closeButtonTrigger: audioMoreActionBottomView.closeButton.rx.tap.asDriver())
let output = viewModel.transform(input: input)
let dataSource = AudioMoreActionController.dataSource()
@ -74,6 +75,27 @@ class AudioMoreActionController: ViewController, UIScrollViewDelegate {
output.itemSelected.subscribe { sectionItem in
}.disposed(by: rx.disposeBag)
output.selection.drive { indexPath in
guard let vc = self.presentingViewController else { return }
self.navigator.dismiss(sender: self)
let share = ShareActionViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .share(viewModel: share), sender: vc, transition: .navigationPresent(type: .share))
}.disposed(by: rx.disposeBag)
audioMoreActionBottomView.closeButton.rx.tap.subscribe { _ in
self.navigator.dismiss(sender: self)
}.disposed(by: rx.disposeBag)
}
override func viewDidLayoutSubviews() {
@ -113,9 +135,22 @@ extension AudioMoreActionController {
let cell: AudioMoreActionViewCell = tableView.dequeueReusableCell(withIdentifier: "AudioMoreActionViewCell", for: indexPath) as! AudioMoreActionViewCell
cell.audioMoreAction = item
return cell
}
)
}
}
extension AudioMoreActionController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let carePresentationVC = CardPresentationController.init(presentedViewController: presented, presenting: presenting)
carePresentationVC.viewType = .audioMore
return carePresentationVC
}
}

@ -95,6 +95,12 @@ class AudioMoreActionBottomView: UIView {
return closeButton
}()
let lineView: UIView = {
let lineView = UIView.init()
lineView.backgroundColor = .separator()
return lineView
}()
override init(frame: CGRect) {
super.init(frame: frame)
@ -106,12 +112,22 @@ class AudioMoreActionBottomView: UIView {
}
func makeUI() {
backgroundColor = .white
addSubview(closeButton)
addSubview(lineView)
}
override func layoutSubviews() {
super.layoutSubviews()
lineView.snp.makeConstraints { make in
make.top.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
make.height.equalTo(1)
}
closeButton.snp.makeConstraints { make in
make.left.equalTo(self)
make.right.equalTo(self)
@ -125,24 +141,34 @@ class AudioMoreActionBottomView: UIView {
class AudioMoreActionViewCell: UITableViewCell {
var iconView: UIImageView = {
let iconView = UIImageView.init()
iconView.backgroundColor = .red
iconView.setContentHuggingPriority(.required, for: .horizontal)
iconView.setContentCompressionResistancePriority(.required, for: .horizontal)
return iconView
}()
var titleLabel: UILabel = {
let titleLabel = UILabel.init()
titleLabel.font = UIFont.systemFont(ofSize: 15)
titleLabel.backgroundColor = .red
titleLabel.text = "rtest"
titleLabel.textColor = .primaryText()
return titleLabel
}()
var audioMoreAction: AudioMoreAction? {
didSet {
guard let audioMoreAction = audioMoreAction else { return }
iconView.image = UIImage.init(named: audioMoreAction.icon)
titleLabel.text = audioMoreAction.title
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
makeUI()
}

@ -14,6 +14,8 @@ class AudioMoreActionViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
let closeButtonTrigger: Driver<Void>
}
@ -33,9 +35,9 @@ class AudioMoreActionViewModel: ViewModel, ViewModelType {
}.disposed(by: rx.disposeBag)
let share = AudioMoreAction.init(icon: "share", title: "分享")
let like = AudioMoreAction.init(icon: "like", title: "收藏")
let download = AudioMoreAction.init(icon: "download", title: "下载")
let share = AudioMoreAction.init(icon: "audio_share_btn", title: "分享")
let like = AudioMoreAction.init(icon: "audio_like_off", title: "收藏")
let download = AudioMoreAction.init(icon: "audio_download_btn", title: "下载")
let selection = AudioMoreActionSection.init(items: [share, like, download])
items.accept([selection])

@ -11,7 +11,7 @@ import RxCocoa
import RxDataSources
class JournalDetailController: TableViewController {
class JournalDetailController: ViewController, UIScrollViewDelegate {
lazy var headerView: JournalDetailHeaderView = {
let headerView = JournalDetailHeaderView.init()
@ -20,11 +20,29 @@ class JournalDetailController: TableViewController {
return headerView
}()
lazy var tableView: TableView = {
let tableView = TableView(frame: CGRect(), style: .grouped)
// view.emptyDataSetSource = self
// view.emptyDataSetDelegate = self
tableView.rx.setDelegate(self).disposed(by: rx.disposeBag)
return tableView
}()
var commentToolView: CommentToolView = {
let commentToolView = CommentToolView.init()
return commentToolView
}()
override func viewDidLoad() {
super.viewDidLoad()
}
@ -32,13 +50,20 @@ class JournalDetailController: TableViewController {
override func makeUI() {
super.makeUI()
view.addSubview(commentToolView)
view.addSubview(tableView)
tableView.tableHeaderView = headerView
tableView.register(SongViewCell.self, forCellReuseIdentifier: "SongViewCell")
updateText(text: "")
headerView.isExpand = false
tableView.mj_header = nil
tableView.mj_footer = nil
}
override func bindViewModel() {
@ -47,31 +72,52 @@ class JournalDetailController: TableViewController {
guard let viewModel = viewModel as? JournalDetailViewModel else { return }
let input = JournalDetailViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
selection: tableView.rx.itemSelected.asDriver(),
dropButtonTrigger: headerView.dropButton.rx.tap.asDriver(),
playButtonTrigger: headerView.playButton.rx.tap.asDriver(),
shareButtonTrigger: headerView.playButton.rx.tap.asDriver())//TODO
let output = viewModel.transform(input: input)
let dataSource = JournalDetailController.dataSource()
let dataSource = JournalDetailController.dataSource { cell, audioTrack in
let audioMoreActionViewModel = AudioMoreActionViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .audioMore(viewModel: audioMoreActionViewModel), sender: self, transition: .navigationPresent(type: .audioMore))
}
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
let vm = AudioMoreActionViewModel.init(provider: viewModel.provider)
let audioMoreAction = AudioMoreActionController.init(viewModel: vm, navigator: self.navigator!)
self.present(audioMoreAction, animated: true)
switch sectionItem {
default: break
}
}.disposed(by: rx.disposeBag)
// _ = self.headerView.dropButton.rx.isSelected <-> viewModel.isExpand
viewModel.isExpand
.bind(to: self.headerView.dropButton.rx.isSelected)
.disposed(by: rx.disposeBag)
viewModel.isExpand.subscribe { isExpand in
print("dropButtonTrigger \(isExpand)")
self.headerView.isExpand = isExpand
self.updateHeader()
} .disposed(by: rx.disposeBag)
if let tabbar = self.tabBarController as? HomeTabBarController {
tabbar.showTabBar(false, animated: true)
}
}
func updateText(text: String) {
@ -111,7 +157,21 @@ class JournalDetailController: TableViewController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateHeader()
commentToolView.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.bottom.equalTo(view)
make.height.equalTo(BaseDimensions.bottomHeight + 48)
}
tableView.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.bottom.equalTo(commentToolView.snp.top)
make.top.equalTo(view)
}
}
@ -119,12 +179,16 @@ class JournalDetailController: TableViewController {
extension JournalDetailController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<JournalSection> {
static func dataSource(_ buttonTapHandler: @escaping (UITableViewCell, AudioTrack) -> Void) -> RxTableViewSectionedReloadDataSource<JournalSection> {
return RxTableViewSectionedReloadDataSource<JournalSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: SongViewCell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as! SongViewCell
cell.audio = item
cell.audioTrack = item
cell.buttonTapCallback = {audioTrack in
buttonTapHandler(cell, audioTrack)
}
return cell
}

@ -299,6 +299,8 @@ class JournalDetailView: UIView {
}
func makeUI() {
backgroundColor = .white
addSubview(countLabel)
addSubview(downloadButton)
addSubview(likeButton)
@ -383,3 +385,58 @@ class JournalDetailToolView: UIView {
}
class CommentToolView: UIView {
let commentCountButton: CommentCountButton = {
let commentCountButton = CommentCountButton.init()
commentCountButton.setContentHuggingPriority(.required, for: .horizontal)
commentCountButton.setContentCompressionResistancePriority(.required, for: .horizontal)
return commentCountButton
}()
let textField: UITextField = {
let textField = UITextField.init()
textField.layer.cornerRadius = 19
textField.backgroundColor = .init(hex: 0x000000, alpha: 0.05)
textField.placeholder = "说点想说的"
return textField
}()
override init(frame: CGRect) {
super.init(frame: frame)
makeUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func makeUI() {
backgroundColor = .white
addSubview(textField)
addSubview(commentCountButton)
}
override func layoutSubviews() {
super.layoutSubviews()
commentCountButton.snp.makeConstraints { make in
make.right.equalTo(self).offset(-6)
make.top.equalTo(self).offset(20)
make.height.equalTo(24)
}
textField.snp.makeConstraints { make in
make.right.equalTo(commentCountButton.snp.left).offset(-14)
make.centerY.equalTo(commentCountButton)
make.left.equalTo(self).offset(18)
make.height.equalTo(38)
}
}
}

@ -14,6 +14,11 @@ class JournalDetailViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
let dropButtonTrigger: Driver<Void>
let playButtonTrigger: Driver<Void>
let shareButtonTrigger: Driver<Void>
// let moreButtonTrigger: Driver<AudioTrack>
}
@ -21,32 +26,68 @@ class JournalDetailViewModel: ViewModel, ViewModelType {
let items: BehaviorRelay<[JournalSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<AudioTrack>
let journalDetail: PublishSubject<JournalDetail>
let currentPlaying: PublishSubject<AudioTrack>
let dowloadState: Driver<Float>
let isLike: BehaviorRelay<Bool>
let isExpand: BehaviorRelay<Bool>
}
let itemSelected = PublishSubject<AudioTrack>()
let items = BehaviorRelay<[JournalSection]>.init(value: [])
let isExpand = BehaviorRelay<Bool>.init(value: false)
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let journal = AudioTrack.init(artists: [], availableMarkets: [""], discNumber: 0, durationMs: 0, explicit: false, externalUrls: ["": ""], id: "", name: "123", previewUrl: "")
items.accept([JournalSection.init(items: [journal, journal, journal, journal], isDownloaded: false, isLike: false)])
input.dropButtonTrigger.drive { _ in
self.isExpand.accept(!self.isExpand.value)
}.disposed(by: rx.disposeBag)
let journalDetail = JournalDetail.init(audio: "", cover: "", title: "", artist: "", number: "", tags: [], date: 0, content: "", isExpand: false)
let item = AudioTrack.init(artists: [], availableMarkets: [""], discNumber: 0, durationMs: 0, explicit: false, externalUrls: ["": ""], id: "", name: "123", previewUrl: "")
let journalSection = JournalSection.init(items: [item, item, item, item], journalDetail: journalDetail)
items.accept([journalSection])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
self.itemSelected.onNext(sectionItem)
}.disposed(by: rx.disposeBag)
let journal = PublishSubject<JournalDetail>.init()
let currentPlaying: PublishSubject<AudioTrack> = .init()
let dowloadState: Driver<Float> = .just(0)
let isLike = BehaviorRelay<Bool>.init(value: false)
let isLick = BehaviorRelay<Bool>.init(value: false)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
itemSelected: itemSelected,
journalDetail: journal,
currentPlaying: currentPlaying,
dowloadState: dowloadState,
isLike: isLike,
isExpand: isExpand
)
}
}

@ -15,19 +15,21 @@ class ShareActionController: ViewController {
var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
// layout.headerReferenceSize = CGSize(width: collectionView.frame.size.width, height: 50)
layout.sectionInset = UIEdgeInsets.init(top: 0, left: 15, bottom: 0, right: 15)
layout.itemSize = CGSize(width: 46, height: 77)
layout.scrollDirection = .horizontal
// layout.minimumInteritemSpacing = 50 //
layout.minimumLineSpacing = 24 //
let collectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.register(ShareActionViewCell.self, forCellWithReuseIdentifier: "ShareActionViewCell")
collectionView.showsHorizontalScrollIndicator = false
return collectionView
}()
var audioMoreActionBottomView: AudioMoreActionBottomView = {
let audioMoreActionBottomView = AudioMoreActionBottomView.init()
audioMoreActionBottomView.backgroundColor = .blue
return audioMoreActionBottomView
}()
@ -54,7 +56,7 @@ class ShareActionController: ViewController {
guard let viewModel = viewModel as? ShareActionViewModel else { return }
let input = ShareActionViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: collectionView.rx.itemSelected.asDriver())
selection: collectionView.rx.itemSelected.asDriver(),closeButtonTrigger: audioMoreActionBottomView.closeButton.rx.tap.asDriver())
let output = viewModel.transform(input: input)
let dataSource = ShareActionController.dataSource()
@ -65,6 +67,13 @@ class ShareActionController: ViewController {
output.itemSelected.subscribe { sectionItem in
}.disposed(by: rx.disposeBag)
audioMoreActionBottomView.closeButton.rx.tap.subscribe { _ in
self.navigator.dismiss(sender: self)
}.disposed(by: rx.disposeBag)
}
override func viewDidLayoutSubviews() {
@ -97,10 +106,25 @@ extension ShareActionController {
return RxCollectionViewSectionedReloadDataSource<ShareActionSection>(
configureCell: { dataSource, collectionView, indexPath, item in
// cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ShareActionViewCell", for: indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ShareActionViewCell", for: indexPath) as! ShareActionViewCell
// cell
cell.titleLabel.text = item.title
return cell
}
)
}
}
extension ShareActionController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let carePresentationVC = CardPresentationController.init(presentedViewController: presented, presenting: presenting)
carePresentationVC.viewType = .share
return carePresentationVC
}
}

@ -20,8 +20,8 @@ class ShareActionViewCell: UICollectionViewCell {
let titleLabel = UILabel.init()
titleLabel.font = UIFont.systemFont(ofSize: 15)
titleLabel.backgroundColor = .red
titleLabel.textAlignment = .center
titleLabel.text = "rtest"
return titleLabel
}()
@ -38,8 +38,8 @@ class ShareActionViewCell: UICollectionViewCell {
func makeUI() {
addSubview(iconView)
addSubview(titleLabel)
contentView.addSubview(iconView)
contentView.addSubview(titleLabel)
iconView.snp.makeConstraints { make in
make.size.equalTo(CGSize.init(width: 46, height: 46))

@ -14,7 +14,7 @@ class ShareActionViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
let closeButtonTrigger: Driver<Void>
}
struct Output {
@ -35,7 +35,7 @@ class ShareActionViewModel: ViewModel, ViewModelType {
let share = Share.init(icon: "share", title: "微信")
let selection = ShareActionSection.init(items: [share])
let selection = ShareActionSection.init(items: [share, share , share , share, share, share])
items.accept([selection])
input.selection.drive { indexPath in

@ -12,7 +12,23 @@ import RxDataSources
class MusicStyleViewController: ViewController {
let collectionView: UICollectionView = {
let collectionView = UICollectionView.init()
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 15
layout.minimumLineSpacing = 24
layout.sectionInset = UIEdgeInsets.init(top: 0, left: 18, bottom: 0, right: 18)
layout.itemSize = CGSize(width: (BaseDimensions.screenWidth - 18 * 2 - 15) / 2, height: 147)
let collectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.register(MusicStyleCellView.self, forCellWithReuseIdentifier: "MusicStyleCellView")
collectionView.register(MusicStyleHeaderView.self, forSupplementaryViewOfKind: "UICollectionElementKindSectionHeader", withReuseIdentifier: "MusicStyleHeaderView")
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.headerReferenceSize = CGSize(width: collectionView.frame.width, height: 360) // header
}
return collectionView
}()
@ -34,19 +50,65 @@ class MusicStyleViewController: ViewController {
super.makeUI()
view.addSubview(collectionView)
}
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? MusicStyleViewModel else { return }
let input = MusicStyleViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: collectionView.rx.itemSelected.asDriver(),
dropButtonTrigger: headerView.dropButton.rx.tap.asDriver())
let output = viewModel.transform(input: input)
let dataSource = MusicStyleViewController.dataSource()
output.items.bind(to: collectionView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
switch sectionItem {
default: break
}
}.disposed(by: rx.disposeBag)
// _ = self.headerView.dropButton.rx.isSelected <-> viewModel.isExpand
viewModel.isExpand
.bind(to: self.headerView.dropButton.rx.isSelected)
.disposed(by: rx.disposeBag)
viewModel.isExpand.subscribe { isExpand in
print("dropButtonTrigger \(isExpand)")
self.headerView.isExpand = isExpand
self.updateHeader()
} .disposed(by: rx.disposeBag)
if let tabbar = self.tabBarController as? HomeTabBarController {
tabbar.showTabBar(false, animated: true)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.snp.makeConstraints { make in
make.edges.equalTo(view)
}
}
func updateText(text: String) {
@ -77,24 +139,41 @@ extension MusicStyleViewController: UICollectionViewDelegateFlowLayout {
return CGSize(width: collectionView.bounds.width, height: size.height)
}
static func dataSource() -> RxCollectionViewSectionedReloadDataSource<MusicStyleSection> {
return RxCollectionViewSectionedReloadDataSource<MusicStyleSection>(
configureCell: { dataSource, collectionView, indexPath, item in
// cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicStyleCellView", for: indexPath)
// cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicStyleCellView", for: indexPath) as! MusicStyleCellView
cell.titleLabel.text = item.title
cell.volLabel.text = item.subTitle
return cell
},
configureSupplementaryView: { dataSource, collectionView, kind, indexPath in
guard kind == UICollectionView.elementKindSectionHeader else {
return UICollectionReusableView()
}
let section = dataSource[indexPath.section]
let resuableView = collectionView.dequeueReusableSupplementaryView(ofKind: "UICollectionElementKindSectionHeader", withReuseIdentifier: "MusicStyleHeaderView", for: indexPath) as! MusicStyleHeaderView
resuableView.styleLabel.text = section.header
resuableView.subStyleLabel.text = section.headerSub
resuableView.contentLabel.text = section.content
resuableView.dropButton.isSelected = section.isExpand
return resuableView
}
)
}
}
class MusicStyleHeaderView: UIView {
class MusicStyleHeaderView: UICollectionReusableView {
let titleImageView: UIImageView = {
let titleImageView = UIImageView.init()
titleImageView.backgroundColor = .blue
return titleImageView
}()
@ -105,6 +184,7 @@ class MusicStyleHeaderView: UIView {
containerView.layer.cornerRadius = 8
containerView.layer.masksToBounds = true
containerView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
containerView.backgroundColor = .white
return containerView
}()
@ -204,6 +284,7 @@ class MusicStyleHeaderView: UIView {
containerView.addSubview(subStyleLabel)
containerView.addSubview(contentLabel)
containerView.addSubview(dropButton)
}
override func layoutSubviews() {
@ -260,7 +341,7 @@ class MusicStyleCellView: UICollectionViewCell {
titleImageView.layer.cornerRadius = 8
titleImageView.layer.masksToBounds = true
titleImageView.backgroundColor = .red
return titleImageView
}()

@ -0,0 +1,75 @@
//
// MusicStyleViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/5.
//
import Foundation
import RxSwift
import RxCocoa
class MusicStyleViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
let dropButtonTrigger: Driver<Void>
}
struct Output {
let items: BehaviorRelay<[MusicStyleSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<MusicStyle>
let isExpand: BehaviorRelay<Bool>
}
let itemSelected = PublishSubject<MusicStyle>()
let items = BehaviorRelay<[MusicStyleSection]>.init(value: [])
let isExpand = BehaviorRelay<Bool>.init(value: false)
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
input.dropButtonTrigger.drive { _ in
self.isExpand.accept(!self.isExpand.value)
}.disposed(by: rx.disposeBag)
let item = MusicStyle.init(title: "测试", subTitle: "123", backgroundImage: "")
let musicStyleSection = MusicStyleSection.init(items: [item, item, item, item], header: "后摇", headerSub: "Post Rock", content: "总在不经意间获得简单朴素且乐趣其中的感怀,这种感怀的妙处在于它没有试图去提炼出任何的真理,他就像我们恬然的谈话里总夹杂着“那我懂你的意思了”,但是否是真的明白,却不然得知。即", isExpand: false)
items.accept([musicStyleSection])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
self.itemSelected.onNext(sectionItem)
}.disposed(by: rx.disposeBag)
let journal = PublishSubject<JournalDetail>.init()
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected,
isExpand: isExpand
)
}
}

@ -279,7 +279,7 @@ extension SearchResultsView {
configureCell: { dataSource, tableView, indexPath, item in
let cell: SongViewCell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as! SongViewCell
cell.audio = item
cell.audioTrack = item
return cell
}

@ -13,9 +13,17 @@ import RxDataSources
class SearchViewController: ViewController, UIScrollViewDelegate {
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 15
layout.minimumLineSpacing = 15
layout.sectionInset = UIEdgeInsets.init(top: 0, left: 18, bottom: 0, right: 18)
layout.itemSize = CGSize(width: (BaseDimensions.screenWidth - 18 * 2 - 15) / 2, height: 88)
let collectionView = UICollectionView.init(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.register(SearchViewCell.self, forCellWithReuseIdentifier: "SearchViewCell")
collectionView.register(SearchHeaderView.self, forSupplementaryViewOfKind: "UICollectionElementKindSectionHeader", withReuseIdentifier: "SearchHeaderView")
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
@ -35,6 +43,8 @@ class SearchViewController: ViewController, UIScrollViewDelegate {
}
override func makeUI() {
super.makeUI()
@ -44,6 +54,30 @@ class SearchViewController: ViewController, UIScrollViewDelegate {
}
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? SearchViewModel else { return }
let input = SearchViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: collectionView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = SearchViewController.dataSource()
output.items.bind(to: collectionView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
let musicStyleViewModel = MusicStyleViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .musicStyle(viewModel: musicStyleViewModel), sender: self)
}.disposed(by: rx.disposeBag)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
@ -59,7 +93,11 @@ extension SearchViewController {
static func dataSource() -> RxCollectionViewSectionedReloadDataSource<SearchSection> {
return RxCollectionViewSectionedReloadDataSource<SearchSection>(
configureCell: { dataSource, collectionView, indexPath, item in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchViewCell", for: indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchViewCell", for: indexPath) as! SearchViewCell
cell.titleLabel.text = item.title
cell.subTitleLabel.text = item.subTitle
return cell
},
configureSupplementaryView: { dataSource, collectionView, kind, indexPath in
@ -81,6 +119,7 @@ class SearchViewCell: UICollectionViewCell {
let backgroudnView = UIImageView.init()
backgroudnView.layer.cornerRadius = 8
backgroudnView.layer.masksToBounds = true
backgroudnView.backgroundColor = .red
return backgroudnView
}()
@ -113,6 +152,7 @@ class SearchViewCell: UICollectionViewCell {
func makeUI() {
contentView.addSubview(backgroudnView)
contentView.addSubview(titleLabel)
contentView.addSubview(subTitleLabel)
@ -148,6 +188,9 @@ class SearchHeaderView: UICollectionReusableView {
let searchControl: SearchControl = {
let searchControl = SearchControl.init()
searchControl.layer.cornerRadius = 20
searchControl.layer.borderColor = UIColor.primaryText().cgColor
searchControl.layer.borderWidth = 1
return searchControl
}()
@ -192,6 +235,8 @@ class SearchControl: UIControl {
let iconView: UIImageView = {
let iconView = UIImageView.init()
iconView.image = UIImage.init(named: "search_bar_icon")
iconView.setContentHuggingPriority(.required, for: .horizontal)
iconView.setContentCompressionResistancePriority(.required, for: .horizontal)
return iconView
}()

@ -6,20 +6,46 @@
//
import Foundation
import RxSwift
import RxCocoa
class SearchViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SearchSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Search>
}
let itemSelected = PublishSubject<Search>()
let items = BehaviorRelay<[SearchSection]>.init(value: [])
func transform(input: Input) -> Output {
let search = Search.init(title: "硬核", subTitle: "Hardcore", backgroundImage: "")
let searchSection = SearchSection.init(items: [search, search, search, search, search])
items.accept([searchSection])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
self.itemSelected.onNext(sectionItem)
}.disposed(by: rx.disposeBag)
return Output()
return Output(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

@ -17,5 +17,8 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}

Loading…
Cancel
Save