Set the module interaction logic to write

dev
wenlei 11 months ago
parent c8a3ef59ca
commit 1062a4c0e3

@ -108,6 +108,10 @@
778B8AC12AF8ED280034AFD4 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 778B8AB82AF8ED280034AFD4 /* TableView.swift */; };
778B8AC22AF8ED280034AFD4 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 778B8AB92AF8ED280034AFD4 /* TableViewController.swift */; };
778B8AC32AF8ED280034AFD4 /* TabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 778B8ABA2AF8ED280034AFD4 /* TabViewController.swift */; };
77C9B9BE2B4AB4FA0006C83F /* TimingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9B9BD2B4AB4FA0006C83F /* TimingViewModel.swift */; };
77C9B9C02B4AB5B50006C83F /* PrivacyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9B9BF2B4AB5B50006C83F /* PrivacyViewModel.swift */; };
77C9B9C22B4AB6C10006C83F /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9B9C12B4AB6C10006C83F /* AboutViewModel.swift */; };
77C9B9C42B4AB75E0006C83F /* CacheViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9B9C32B4AB75E0006C83F /* CacheViewModel.swift */; };
77FA0B282B0B3E1E00404C5E /* Journal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FA0B272B0B3E1E00404C5E /* Journal.swift */; };
77FA0B2A2B0B5F0D00404C5E /* AudioMoreActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FA0B292B0B5F0D00404C5E /* AudioMoreActionView.swift */; };
77FA0B2C2B0C480B00404C5E /* AudioMoreActionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FA0B2B2B0C480B00404C5E /* AudioMoreActionViewModel.swift */; };
@ -140,6 +144,11 @@
77FB7A702B48074600B64030 /* MusicStyleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */; };
77FB7A722B48E93100B64030 /* SearchResultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A712B48E93100B64030 /* SearchResultsViewModel.swift */; };
77FB7A742B49944E00B64030 /* ScrollSegmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A732B49944E00B64030 /* ScrollSegmentView.swift */; };
77FB7A762B4A4B5600B64030 /* MineJournalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A752B4A4B5600B64030 /* MineJournalViewController.swift */; };
77FB7A782B4A4B6400B64030 /* MineJournalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A772B4A4B6400B64030 /* MineJournalViewModel.swift */; };
77FB7A7B2B4A4FC900B64030 /* MessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */; };
77FB7A7D2B4A4FD400B64030 /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */; };
77FB7A7F2B4A630100B64030 /* ThanksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FB7A7E2B4A630100B64030 /* ThanksViewModel.swift */; };
B570F70B7040469E9D729E7E /* Pods_IndieMusic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA421D41748C113CCE36A32 /* Pods_IndieMusic.framework */; };
/* End PBXBuildFile section */
@ -270,6 +279,10 @@
778B8AB82AF8ED280034AFD4 /* TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = "<group>"; };
778B8AB92AF8ED280034AFD4 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = "<group>"; };
778B8ABA2AF8ED280034AFD4 /* TabViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabViewController.swift; sourceTree = "<group>"; };
77C9B9BD2B4AB4FA0006C83F /* TimingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimingViewModel.swift; sourceTree = "<group>"; };
77C9B9BF2B4AB5B50006C83F /* PrivacyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyViewModel.swift; sourceTree = "<group>"; };
77C9B9C12B4AB6C10006C83F /* AboutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewModel.swift; sourceTree = "<group>"; };
77C9B9C32B4AB75E0006C83F /* CacheViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheViewModel.swift; sourceTree = "<group>"; };
77FA0B272B0B3E1E00404C5E /* Journal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Journal.swift; sourceTree = "<group>"; };
77FA0B292B0B5F0D00404C5E /* AudioMoreActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMoreActionView.swift; sourceTree = "<group>"; };
77FA0B2B2B0C480B00404C5E /* AudioMoreActionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMoreActionViewModel.swift; sourceTree = "<group>"; };
@ -302,6 +315,11 @@
77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicStyleViewModel.swift; sourceTree = "<group>"; };
77FB7A712B48E93100B64030 /* SearchResultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewModel.swift; sourceTree = "<group>"; };
77FB7A732B49944E00B64030 /* ScrollSegmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollSegmentView.swift; sourceTree = "<group>"; };
77FB7A752B4A4B5600B64030 /* MineJournalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineJournalViewController.swift; sourceTree = "<group>"; };
77FB7A772B4A4B6400B64030 /* MineJournalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineJournalViewModel.swift; sourceTree = "<group>"; };
77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewController.swift; sourceTree = "<group>"; };
77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = "<group>"; };
77FB7A7E2B4A630100B64030 /* ThanksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThanksViewModel.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>"; };
@ -529,6 +547,7 @@
778B8A582AF8EAED0034AFD4 /* Modules */ = {
isa = PBXGroup;
children = (
77FB7A792B4A4FB600B64030 /* Message */,
774A180C2B06FFF500F56DF1 /* JournalDetail */,
7743999C2AFA18B0006F8EEA /* Player */,
778B8A762AF8ECE50034AFD4 /* Home */,
@ -614,6 +633,8 @@
77FA0B512B0F3BC700404C5E /* MineView.swift */,
77FA0B552B0F4ABF00404C5E /* MineSingleController.swift */,
77FA0B572B0F4C0800404C5E /* MineSingleViewModel.swift */,
77FB7A752B4A4B5600B64030 /* MineJournalViewController.swift */,
77FB7A772B4A4B6400B64030 /* MineJournalViewModel.swift */,
);
path = Mine;
sourceTree = "<group>";
@ -650,10 +671,15 @@
7751D3632B42BC2E00F1F2BD /* AccountViewModel.swift */,
7751D3652B42BE7F00F1F2BD /* FeedbackViewController.swift */,
7751D3672B42E96200F1F2BD /* ThanksViewController.swift */,
77FB7A7E2B4A630100B64030 /* ThanksViewModel.swift */,
7751D3692B42ED6C00F1F2BD /* TimingViewController.swift */,
77C9B9BD2B4AB4FA0006C83F /* TimingViewModel.swift */,
7751D36D2B43A03E00F1F2BD /* PrivacyViewController.swift */,
77C9B9BF2B4AB5B50006C83F /* PrivacyViewModel.swift */,
7751D36B2B439F0000F1F2BD /* AboutViewController.swift */,
77C9B9C12B4AB6C10006C83F /* AboutViewModel.swift */,
7751D36F2B43A4FC00F1F2BD /* CacheViewController.swift */,
77C9B9C32B4AB75E0006C83F /* CacheViewModel.swift */,
);
path = Setting;
sourceTree = "<group>";
@ -680,6 +706,15 @@
path = "RxSwift+Extension";
sourceTree = "<group>";
};
77FB7A792B4A4FB600B64030 /* Message */ = {
isa = PBXGroup;
children = (
77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */,
77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */,
);
path = Message;
sourceTree = "<group>";
};
8E5A57ACCF64265CA660700B /* Pods */ = {
isa = PBXGroup;
children = (
@ -964,6 +999,7 @@
7751D35C2B42B5E900F1F2BD /* EditInfoViewModel.swift in Sources */,
7751D3602B42BA3D00F1F2BD /* EditNameController.swift in Sources */,
778B8A212AF8E36D0034AFD4 /* AppDelegate.swift in Sources */,
77FB7A762B4A4B5600B64030 /* MineJournalViewController.swift in Sources */,
778B8AC32AF8ED280034AFD4 /* TabViewController.swift in Sources */,
77FAF7622B07434A00FC2CA1 /* AudioMoreActionController.swift in Sources */,
774A18122B07327C00F56DF1 /* CommentCountButton.swift in Sources */,
@ -1010,13 +1046,17 @@
7751D37E2B451EA800F1F2BD /* UserDefaultKeys.swift in Sources */,
778B8A8E2AF8ECF20034AFD4 /* Artist.swift in Sources */,
774A17F32B0459C900F56DF1 /* PlayerViewModel.swift in Sources */,
77FB7A782B4A4B6400B64030 /* MineJournalViewModel.swift in Sources */,
778B8A6D2AF8ECD30034AFD4 /* Observable+Operators.swift in Sources */,
77FA0B542B0F447400404C5E /* Mine.swift in Sources */,
77C9B9C02B4AB5B50006C83F /* PrivacyViewModel.swift in Sources */,
77FB7A7F2B4A630100B64030 /* ThanksViewModel.swift in Sources */,
778B8ABB2AF8ED280034AFD4 /* WebViewController.swift in Sources */,
774A17F72B04932100F56DF1 /* SegmentControl.swift in Sources */,
77FA0B282B0B3E1E00404C5E /* Journal.swift in Sources */,
77FA0B5A2B147EC900404C5E /* CommentViewController.swift in Sources */,
77FA0B402B0D8E9300404C5E /* LayoutableButton.swift in Sources */,
77C9B9C22B4AB6C10006C83F /* AboutViewModel.swift in Sources */,
778B8A712AF8ECD30034AFD4 /* Api.swift in Sources */,
77FA0B582B0F4C0800404C5E /* MineSingleViewModel.swift in Sources */,
77FA0B342B0C50BA00404C5E /* ShareActionViewModel.swift in Sources */,
@ -1035,6 +1075,7 @@
7751D3582B42B5A200F1F2BD /* EditInfoViewController.swift in Sources */,
774A180B2B06F8B900F56DF1 /* JournalDetailController.swift in Sources */,
7751D3522B42AC2B00F1F2BD /* SettingView.swift in Sources */,
77C9B9BE2B4AB4FA0006C83F /* TimingViewModel.swift in Sources */,
77FA0B362B0C50D800404C5E /* Share.swift in Sources */,
778B8A622AF8ECC20034AFD4 /* ErrorTracker.swift in Sources */,
774A18102B070A6900F56DF1 /* SongViewCell.swift in Sources */,
@ -1050,6 +1091,7 @@
778B8A702AF8ECD30034AFD4 /* ErrorResponse.swift in Sources */,
77FA0B2A2B0B5F0D00404C5E /* AudioMoreActionView.swift in Sources */,
778B8A6C2AF8ECD30034AFD4 /* Networking.swift in Sources */,
77C9B9C42B4AB75E0006C83F /* CacheViewModel.swift in Sources */,
77FA0B2E2B0C485D00404C5E /* AudioMoreAction.swift in Sources */,
7751D37C2B4516BE00F1F2BD /* UILabel+IndieMusic.swift in Sources */,
778B8AAC2AF8ED0E0034AFD4 /* UIViewController+Rx.swift in Sources */,
@ -1063,10 +1105,12 @@
77FA0B3E2B0C573600404C5E /* Filter.swift in Sources */,
77165D742B464493002AE0A5 /* BarButtonItem.swift in Sources */,
7751D3662B42BE7F00F1F2BD /* FeedbackViewController.swift in Sources */,
77FB7A7B2B4A4FC900B64030 /* MessageViewController.swift in Sources */,
77FB7A722B48E93100B64030 /* SearchResultsViewModel.swift in Sources */,
774A18142B07329600F56DF1 /* MultiUserAvatarView.swift in Sources */,
778B8AAA2AF8ED0E0034AFD4 /* AVPlayer.swift in Sources */,
77FA0B442B0DFABD00404C5E /* LoginView.swift in Sources */,
77FB7A7D2B4A4FD400B64030 /* MessageViewModel.swift in Sources */,
7743999E2AFA18C3006F8EEA /* PlayerViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

@ -26,6 +26,19 @@ class Navigator {
case audioMore(viewModel: AudioMoreActionViewModel)
case share(viewModel: ShareActionViewModel)
case musicStyle(viewModel: MusicStyleViewModel)
case mineSingle(viewModel: MineViewModel)
case mineJourna(viewModel: MineJournalViewModel)
case setting(viewModel: SettingViewMdel)
case message(viewModel: MessageViewModel)
case editInfo(viewModel: EditInfoViewModel)
case editName
case account(viewModel: AccountViewModel)
case thanks(viewModel: ThanksViewModel)
case feedback
case timing(viewModel: TimingViewModel)
case privacy(viewModel: PrivacyViewModel)
case about(viewModel: AboutViewModel)
case cache(viewModel: CacheViewModel)
case searchResults(viewModel: SearchResultsViewModel)
@ -76,6 +89,33 @@ class Navigator {
return MusicStyleViewController.init(viewModel: viewModel, navigator: self)
case .searchResults(viewModel: let viewModel):
return SearchResultsController.init(viewModel: viewModel, navigator: self)
case .mineSingle(viewModel: let viewModel):
return MineSingleController.init(viewModel: viewModel, navigator: self)
case .mineJourna(viewModel: let viewModel):
return MineJournalViewController.init(viewModel: viewModel, navigator: self)
case .setting(viewModel: let viewModel):
return SettingViewController.init(viewModel: viewModel, navigator: self)
case .message(viewModel: let viewModel):
return MessageViewController.init(viewModel: viewModel, navigator: self)
case .editInfo(viewModel: let viewModel):
return EditInfoViewController.init(viewModel: viewModel, navigator: self)
case .editName:
return EditNameController.init()
case .account(let viewModel):
return AccountViewController.init(viewModel: viewModel, navigator: self)
case .thanks(let viewModel):
return ThanksViewController.init(viewModel: viewModel, navigator: self)
case .feedback:
return FeedbackViewController.init()
case .timing(viewModel: let viewModel):
return TimingViewController.init(viewModel: viewModel, navigator: self)
case .about(viewModel: let viewModel):
return AboutViewController.init(viewModel: viewModel, navigator: self)
case .cache(viewModel: let viewModel):
return CacheViewController.init(viewModel: viewModel, navigator: self)
case .privacy(viewModel: let viewModel):
return PrivacyViewController.init(viewModel: viewModel, navigator: self)
case .test:
let test = UIViewController.init()
@ -94,6 +134,7 @@ class Navigator {
let vc = WebViewController(viewModel: nil, navigator: self)
vc.load(url: url)
return vc
}
}

@ -309,7 +309,7 @@ extension ScrollSegmentView{
let currWidth = currentWidth - 2 * segmentStyle.titleMargin
titleW = currWidth/CGFloat(labelsArray.count)
titleX = segmentStyle.titleMargin
titleX = 0
if index != 0 {
let lastLabel = labelsArray[index - 1]
titleX = lastLabel.frame.maxX + segmentStyle.titleMargin

@ -52,7 +52,7 @@ class ViewController: UIViewController, Navigatable {
let motionShakeEvent = PublishSubject<Void>()
lazy var backBarButton: BarButtonItem = {
let view = BarButtonItem()
let view = BarButtonItem.init(image: UIImage.init(named: "nav_back_btn"), style: .plain, target: self, action: nil)
view.title = ""
return view
}()
@ -86,6 +86,10 @@ class ViewController: UIViewController, Navigatable {
self?.navigator.dismiss(sender: self)
}).disposed(by: rx.disposeBag)
backBarButton.rx.tap.asObservable().subscribe(onNext: { [weak self] () in
self?.navigator.pop(sender: self)
}).disposed(by: rx.disposeBag)
NotificationCenter.default
.rx.notification(UIDevice.orientationDidChangeNotification).mapToVoid()
.bind(to: orientationEvent).disposed(by: rx.disposeBag)
@ -138,7 +142,6 @@ class ViewController: UIViewController, Navigatable {
func makeUI() {
navigationItem.backBarButtonItem = backBarButton
updateUI()
}
@ -187,7 +190,7 @@ class ViewController: UIViewController, Navigatable {
func adjustLeftBarButtonItem() {
if self.navigationController?.viewControllers.count ?? 0 > 1 { // Pushed
self.navigationItem.leftBarButtonItem = nil
self.navigationItem.leftBarButtonItem = backBarButton
} else if self.presentingViewController != nil { // presented
self.navigationItem.leftBarButtonItem = closeBarButton
}

@ -11,6 +11,7 @@ import RxDataSources
struct Mine: Codable {
let title: String
let detail: String
let isPlaying: Bool
}
struct MineSection {

@ -32,6 +32,35 @@ enum SettingType {
case setting(Setting)
}
extension SettingType {
var setting: Setting {
switch self {
case .editInfo(let setting):
return setting
case .account(let setting):
return setting
case .privacy(let setting):
return setting
case .timing(let setting):
return setting
case .cache(let setting):
return setting
case .permission(let setting):
return setting
case .feedback(let setting):
return setting
case .about(let setting):
return setting
case .contributors(let setting):
return setting
case .version(let setting):
return setting
case .setting(let setting):
return setting
}
}
}
struct SettingSection {
var items: [SettingType]

@ -0,0 +1,19 @@
//
// MessageViewController.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import UIKit
class MessageViewController: ViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

@ -0,0 +1,94 @@
//
// MessageViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class MessageViewModel: 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>
}
struct Output {
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)
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,
journalDetail: journal,
currentPlaying: currentPlaying,
dowloadState: dowloadState,
isLike: isLike,
isExpand: isExpand
)
}
}

@ -0,0 +1,123 @@
//
// MineJournalViewController.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class MineJournalViewController: ViewController {
let mineSingleNoDataView: MineSingleNoDataView = {
let mineSingleNoDataView = MineSingleNoDataView.init()
mineSingleNoDataView.isHidden = true
return mineSingleNoDataView
}()
let collectionView: UICollectionView = {
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")
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func makeUI() {
super.makeUI()
self.navigationItem.title = "期刊"
view.backgroundColor = .white
view.addSubview(mineSingleNoDataView)
view.addSubview(collectionView)
}
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? MineJournalViewModel else { return }
let input = MineJournalViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: collectionView.rx.itemSelected.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)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
mineSingleNoDataView.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.top.equalTo(view)
make.height.equalTo(200)
}
collectionView.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.top.equalTo(view)
make.bottom.equalTo(view)
}
}
}
extension MineJournalViewController {
static func dataSource() -> RxCollectionViewSectionedReloadDataSource<MusicStyleSection> {
return RxCollectionViewSectionedReloadDataSource<MusicStyleSection>(
configureCell: { dataSource, collectionView, indexPath, item in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicStyleCellView", for: indexPath) as! MusicStyleCellView
cell.titleLabel.text = item.title
cell.volLabel.text = item.subTitle
return cell
}
)
}
}

@ -0,0 +1,60 @@
//
// MineJournalViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class MineJournalViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[MusicStyleSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<MusicStyle>
}
let itemSelected = PublishSubject<MusicStyle>()
let items = BehaviorRelay<[MusicStyleSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.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
)
}
}

@ -10,7 +10,13 @@ import RxSwift
import RxCocoa
import RxDataSources
class MineSingleController: TableViewController {
class MineSingleController: TableViewController, UITableViewDataSource {
let mineSingleNoDataView: MineSingleNoDataView = {
let mineSingleNoDataView = MineSingleNoDataView.init()
mineSingleNoDataView.isHidden = true
return mineSingleNoDataView
}()
override func viewDidLoad() {
super.viewDidLoad()
@ -22,7 +28,18 @@ class MineSingleController: TableViewController {
override func makeUI() {
super.makeUI()
self.navigationItem.title = "单曲"
view.backgroundColor = .white
// tableView.delegate = self
tableView.dataSource = self
tableView.register(SongViewCell.self
, forCellReuseIdentifier: "SongViewCell")
tableView.register(MineSingleHeaderView.self, forHeaderFooterViewReuseIdentifier: "MineSingleHeaderView")
view.addSubview(mineSingleNoDataView)
}
override func bindViewModel() {
@ -34,7 +51,14 @@ class MineSingleController: TableViewController {
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = MineSingleController.dataSource()
let dataSource = MineSingleController.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)
@ -47,20 +71,154 @@ class MineSingleController: TableViewController {
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
mineSingleNoDataView.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.top.equalTo(view)
make.height.equalTo(200)
}
}
}
extension MineSingleController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as? SongViewCell {
cell.titleLabel.text = "123"
cell.detailLabel.text = "321"
cell.buttonTapCallback = {[weak self] audioTrack in
guard let viewModel = self?.viewModel as? MineSingleViewModel else { return }
let audioMoreActionViewModel = AudioMoreActionViewModel.init(provider: viewModel.provider)
self?.navigator.show(segue: .audioMore(viewModel: audioMoreActionViewModel), sender: self, transition: .navigationPresent(type: .audioMore))
}
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = MineSingleHeaderView.init()
return header
}
}
extension MineSingleController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<MineSingleSection> {
static func dataSource(_ buttonTapHandler: @escaping (UITableViewCell, AudioTrack) -> Void) -> RxTableViewSectionedReloadDataSource<MineSingleSection> {
return RxTableViewSectionedReloadDataSource<MineSingleSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: SongViewCell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as! SongViewCell
let it = AudioTrack.init(artists: [], availableMarkets: [""], discNumber: 0, durationMs: 0, explicit: false, externalUrls: ["": ""], id: "", name: "123", previewUrl: "")
// cell.titleLabel.text = "123"
// cell.detailLabel.text = "321"
cell.audioTrack = it
cell.buttonTapCallback = {audioTrack in
buttonTapHandler(cell, audioTrack)
}
return cell
}
)
}
}
class MineSingleHeaderView: UITableViewHeaderFooterView {
let playAllButton: UIButton = {
let playAllButton = UIButton.init()
playAllButton.setImage(UIImage.init(named: "audio_playAll_btn"), for: .normal)
playAllButton.setTitle("播放全部", for: .normal)
playAllButton.setTitleColor(.primaryText(), for: .normal)
playAllButton.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
return playAllButton
}()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
makeUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// override init(frame: CGRect) {
// super.init(frame: frame)
//
// makeUI()
// }
func makeUI() {
contentView.backgroundColor = .white
contentView.addSubview(playAllButton)
}
override func layoutSubviews() {
super.layoutSubviews()
playAllButton.snp.makeConstraints { make in
make.left.equalTo(contentView).offset(18)
make.centerY.equalTo(contentView)
}
}
}
class MineSingleNoDataView: UIView {
let titleLabel: UILabel = {
let titleLabel = UILabel.init()
titleLabel.font = UIFont.systemFont(ofSize: 15)
titleLabel.textColor = .init(hex: 0x000000, alpha: 0.6)
titleLabel.text = "你还没收藏过单曲!"
return titleLabel
}()
override init(frame: CGRect) {
super.init(frame: frame)
makeUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func makeUI() {
addSubview(titleLabel)
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel.snp.makeConstraints { make in
make.center.equalTo(self)
}
}
}

@ -297,6 +297,7 @@ class MineViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
makeUI()
}
@ -353,3 +354,4 @@ class MineViewCell: UITableViewCell {
}
}

@ -17,8 +17,35 @@ class MineViewController: TableViewController {
return headerView
}()
lazy var messageBarButton: BarButtonItem = {
let view = BarButtonItem(image: UIImage.init(named: "mine_message_btn"), style: .plain, target: nil, action: nil)
return view
}()
lazy var settingBarButton: BarButtonItem = {
let view = BarButtonItem(image: UIImage.init(named: "mine_setting_btn"), style: .plain, target: nil, action: nil)
return view
}()
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let tabbar = self.tabBarController as? HomeTabBarController {
tabbar.showTabBar(false, animated: true)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let tabbar = self.tabBarController as? HomeTabBarController {
tabbar.showTabBar(true, animated: true)
}
}
override func viewDidLoad() {
@ -30,12 +57,26 @@ class MineViewController: TableViewController {
override func makeUI() {
super.makeUI()
view.backgroundColor = .blue
self.tableView.mj_header = nil
self.tableView.mj_footer = nil
view.backgroundColor = .init(hex: 0xfefefe)
tableView.tableHeaderView = headerView
tableView.separatorColor = .clear
tableView.register(MineViewCell.self, forCellReuseIdentifier: "MineViewCell")
let fixedSpaceBarButtonItem = UIBarButtonItem.init(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
fixedSpaceBarButtonItem.width = -10
navigationItem.rightBarButtonItems = [settingBarButton, fixedSpaceBarButtonItem, messageBarButton]
}
@ -56,6 +97,30 @@ class MineViewController: TableViewController {
output.itemSelected.subscribe { sectionItem in
//
// let mineViewModel = MineViewModel.init(provider: viewModel.provider)
// self.navigator.show(segue: .mineSingle(viewModel: mineViewModel), sender: self)
let mineJournalViewModel = MineJournalViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .mineJourna(viewModel: mineJournalViewModel), sender: self)
}.disposed(by: rx.disposeBag)
settingBarButton.rx.tap.subscribe { _ in
let settingViewModel = SettingViewMdel.init(provider: viewModel.provider)
self.navigator.show(segue: .setting(viewModel: settingViewModel), sender: self)
}.disposed(by: rx.disposeBag)
messageBarButton.rx.tap.subscribe { _ in
let messageViewModel = MessageViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .message(viewModel: messageViewModel), sender: self)
}.disposed(by: rx.disposeBag)
@ -71,8 +136,9 @@ extension MineViewController {
configureCell: { dataSource, tableView, indexPath, item in
let cell: MineViewCell = tableView.dequeueReusableCell(withIdentifier: "MineViewCell", for: indexPath) as! MineViewCell
cell.titleLabel.text = "123"
cell.detailLabel.text = "321"
cell.titleLabel.text = item.title
cell.detailLabel.text = item.detail
cell.playButton.isHidden = !item.isPlaying
return cell
}

@ -23,6 +23,7 @@ class MineViewModel: ViewModel, ViewModelType {
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Mine>
}
let itemSelected = PublishSubject<Mine>()
@ -34,9 +35,11 @@ class MineViewModel: ViewModel, ViewModelType {
}.disposed(by: rx.disposeBag)
let mine = Mine.init(title: "ttt", detail: "123")
let single = Mine.init(title: "单曲", detail: "123", isPlaying: true)
let journal = Mine.init(title: "期刊", detail: "123", isPlaying: false)
let download = Mine.init(title: "下载", detail: "123", isPlaying: false)
items.accept([MineSection.init(items: [mine, mine, mine])])
items.accept([MineSection.init(items: [single, journal, download])])
input.selection.drive { indexPath in

@ -28,14 +28,14 @@ class SearchResultsController: ViewController {
let searchResultsView: SearchResultsView = {
let searchResultsView = SearchResultsView.init()
searchResultsView.tableView.register(SongViewCell.self, forCellReuseIdentifier: "SongViewCell")
searchResultsView.collectionView.register(MusicStyleCellView.self, forCellWithReuseIdentifier: "MusicStyleCellView")
return searchResultsView
}()
override func viewDidLoad() {
super.viewDidLoad()
@ -53,10 +53,55 @@ class SearchResultsController: ViewController {
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
override func bindViewModel() {
super.bindViewModel()
self.searchResultsView.currentSearchType = .single
guard let viewModel = viewModel as? SearchResultsViewModel else { return }
let input = SearchResultsViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
closeButtonTrigger: self.searchTopBar.cancelButton.rx.tap.asDriver(),
collectionViewSelection: searchResultsView.collectionView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let tableViewDataSource = SearchResultsController.tableViewDataSource { cell, audioTrack in
let audioMoreActionViewModel = AudioMoreActionViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .audioMore(viewModel: audioMoreActionViewModel), sender: self, transition: .navigationPresent(type: .audioMore))
}
let collectionViewDataSource = SearchResultsController.collectionViewDataSource()
output.collectionViewItems.bind(to: searchResultsView.collectionView.rx.items(dataSource: collectionViewDataSource)).disposed(by: rx.disposeBag)
output.tableViewItems.bind(to: searchResultsView.tableView.rx.items(dataSource: tableViewDataSource)).disposed(by: rx.disposeBag)
searchTopBar.cancelButton.rx.tap.subscribe { _ in
self.navigator.pop(sender: self)
}.disposed(by: rx.disposeBag)
}
@ -67,7 +112,7 @@ class SearchResultsController: ViewController {
searchTopBar.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.top.equalTo(view).offset(15)
make.top.equalTo(view).offset(BaseDimensions.statusBarHeight + 15)
make.height.equalTo(40)
}
@ -89,6 +134,49 @@ class SearchResultsController: ViewController {
}
extension SearchResultsController {
//TODO
static func tableViewDataSource(_ 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.audioTrack = item
cell.buttonTapCallback = {audioTrack in
buttonTapHandler(cell, audioTrack)
}
return cell
}
)
}
}
extension SearchResultsController {
static func collectionViewDataSource() -> RxCollectionViewSectionedReloadDataSource<MusicStyleSection> {
return RxCollectionViewSectionedReloadDataSource<MusicStyleSection>(
configureCell: { dataSource, collectionView, indexPath, item in
// cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicStyleCellView", for: indexPath) as! MusicStyleCellView
// cell
cell.titleLabel.text = item.title
cell.volLabel.text = item.subTitle
return cell
}
)
}
}
class SearchTopBar: UIView {
let searchControl: SearchControl = {
@ -262,6 +350,17 @@ class SearchResultsView: UIView {
}
func makeUI() {
segmentControl.titleBtnOnClick = { [weak self] (label, index) in
if index == 0 {
self?.currentSearchType = .single
} else {
self?.currentSearchType = .journal
}
}
addSubview(segmentControl)
addSubview(tableView)
addSubview(collectionView)
@ -298,32 +397,3 @@ class SearchResultsView: UIView {
}
extension SearchResultsView {
static func dataSource() -> RxCollectionViewSectionedReloadDataSource<MusicStyleSection> {
return RxCollectionViewSectionedReloadDataSource<MusicStyleSection>(
configureCell: { dataSource, collectionView, indexPath, item in
// cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicStyleCellView", for: indexPath)
// cell
return cell
}
)
}
}
extension SearchResultsView {
//TODO
static func dataSource() -> RxTableViewSectionedReloadDataSource<JournalSection> {
return RxTableViewSectionedReloadDataSource<JournalSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: SongViewCell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as! SongViewCell
cell.audioTrack = item
return cell
}
)
}
}

@ -14,39 +14,60 @@ class SearchResultsViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
let closeButtonTrigger: Driver<Void>
let collectionViewSelection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SearchSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Search>
let tableViewItems: BehaviorRelay<[JournalSection]>
let collectionViewItems: BehaviorRelay<[MusicStyleSection]>
let collectionViewItemSelected: PublishSubject<MusicStyle>
}
let itemSelected = PublishSubject<Search>()
let items = BehaviorRelay<[SearchSection]>.init(value: [])
let tableViewItems = BehaviorRelay<[JournalSection]>.init(value: [])
let collectionViewItemstems = BehaviorRelay<[MusicStyleSection]>.init(value: [])
let collectionViewSelection = PublishSubject<MusicStyle>()
func transform(input: Input) -> Output {
let search = Search.init(title: "硬核", subTitle: "Hardcore", backgroundImage: "")
let searchSection = SearchSection.init(items: [search, search, search, search, search])
input.closeButtonTrigger.drive { _ in
}.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([searchSection])
tableViewItems.accept([journalSection])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
self.itemSelected.onNext(sectionItem)
let musicStyleItem = MusicStyle.init(title: "测试", subTitle: "123", backgroundImage: "")
let musicStyleSection = MusicStyleSection.init(items: [musicStyleItem, musicStyleItem, musicStyleItem, musicStyleItem], header: "后摇", headerSub: "Post Rock", content: "总在不经意间获得简单朴素且乐趣其中的感怀,这种感怀的妙处在于它没有试图去提炼出任何的真理,他就像我们恬然的谈话里总夹杂着“那我懂你的意思了”,但是否是真的明白,却不然得知。即", isExpand: false)
collectionViewItemstems.accept([musicStyleSection])
input.collectionViewSelection.drive { indexPath in
guard let sectionItem = self.collectionViewItemstems.value.first?.items[indexPath.row] else { return }
self.collectionViewSelection.onNext(sectionItem)
}.disposed(by: rx.disposeBag)
return Output(items: items,
selection: input.selection,
itemSelected: itemSelected)
return Output.init(tableViewItems: tableViewItems,
collectionViewItems: collectionViewItemstems, collectionViewItemSelected: collectionViewSelection)
}
}

@ -13,6 +13,7 @@ import RxDataSources
class AboutViewController: TableViewController {
let headerView: EditInfoHeaderView = {
let headerView = EditInfoHeaderView.init(frame: CGRect.init(x: 0, y: 0, width: BaseDimensions.screenWidth, height: 191))
headerView.tipsLabel.text = "版本号1.0.1"
return headerView
}()
@ -32,9 +33,14 @@ class AboutViewController: TableViewController {
override func makeUI() {
super.makeUI()
view.backgroundColor = .blue
view.backgroundColor = .white
tableView.register(MineViewCell.self, forCellReuseIdentifier: "SettingViewCell")
self.navigationItem.title = "关于雀乐"
self.tableView.mj_header = nil
self.tableView.mj_footer = nil
tableView.register(SettingViewCell.self, forCellReuseIdentifier: "SettingViewCell")
tableView.tableHeaderView = headerView
@ -46,13 +52,13 @@ class AboutViewController: TableViewController {
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? MineViewModel else { return }
guard let viewModel = viewModel as? AboutViewModel else { return }
let input = MineViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
let input = AboutViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = MineViewController.dataSource()
let dataSource = AboutViewController.dataSource()
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
@ -73,6 +79,7 @@ class AboutViewController: TableViewController {
make.bottom.equalTo(view).offset(-BaseDimensions.bottomHeight)
make.left.equalTo(view)
make.right.equalTo(view)
make.height.equalTo(100)
}
}
@ -80,13 +87,12 @@ class AboutViewController: TableViewController {
extension AboutViewController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<MineSection> {
return RxTableViewSectionedReloadDataSource<MineSection>(
static func dataSource() -> RxTableViewSectionedReloadDataSource<SettingSection> {
return RxTableViewSectionedReloadDataSource<SettingSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: MineViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! MineViewCell
let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell
cell.setting = item.setting
cell.titleLabel.text = "123"
cell.detailLabel.text = "321"
return cell
}
@ -99,9 +105,15 @@ extension AboutViewController {
class AbloutFooterView: UIView, UITextViewDelegate {
let textView: UITextView = {
let textView = UITextView.init()
textView.addAttributed(attributedes: [("服务条款 ", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? ""]),
(" 版权声明 ", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? ""]),
(" 许可协议", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? ""])
textView.tintColor = UIColor.primary()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineSpacing = 5
textView.addAttributed(attributedes: [("服务条款 ", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? "", NSAttributedString.Key.paragraphStyle: paragraphStyle]),
(" 版权声明 ", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? "" , NSAttributedString.Key.paragraphStyle: paragraphStyle]),
(" 许可协议", [NSAttributedString.Key.foregroundColor: UIColor.primary(), NSAttributedString.Key.link: URL.init(string: Configs.App.aggrementUrl) ?? "", NSAttributedString.Key.paragraphStyle: paragraphStyle])
])
return textView
@ -119,6 +131,7 @@ class AbloutFooterView: UIView, UITextViewDelegate {
}
func makeUI() {
backgroundColor = .white
addSubview(textView)
}
@ -127,7 +140,7 @@ class AbloutFooterView: UIView, UITextViewDelegate {
super.layoutSubviews()
textView.snp.makeConstraints { make in
make.edges.equalTo(self).offset(18)
make.edges.equalTo(self)
}
}

@ -0,0 +1,77 @@
//
// AboutViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class AboutViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
}
let itemSelected = PublishSubject<Setting>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let score = Setting.init(title: "给我们评分", detail: "", arrowIcon: "setting_arrow")
let service = Setting.init(title: "在线客服", detail: "400609213", arrowIcon: "")
let wechat = Setting.init(title: "微信公众号", detail: "雀乐", arrowIcon: "")
//TODO
items.accept([SettingSection.init(items: [.setting(score), .setting(service), .setting(wechat)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
switch sectionItem {
case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
// case .timing(let setting):
// case .cache(let setting):
// case .permission(let setting):
// case .feedback(let setting):
// case .about(let setting):
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
}.disposed(by: rx.disposeBag)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

@ -6,6 +6,9 @@
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class AccountViewController: TableViewController {
@ -16,4 +19,72 @@ class AccountViewController: TableViewController {
}
override func makeUI() {
super.makeUI()
navigationItem.title = "账户与安全"
self.tableView.mj_header = nil
self.tableView.mj_footer = nil
tableView.register(SettingViewCell.self, forCellReuseIdentifier: "SettingViewCell")
view.backgroundColor = .white
}
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? AccountViewModel else { return }
let input = AccountViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = AccountViewController.dataSource()
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
}.disposed(by: rx.disposeBag)
output.selection.drive { sectionItem in
let accountViewModel = AccountViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .account(viewModel: accountViewModel), sender: self)
}.disposed(by: rx.disposeBag)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
}
extension AccountViewController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<SettingSection> {
return RxTableViewSectionedReloadDataSource<SettingSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell
cell.titleLabel.text = item.setting.title
cell.detailLabel.text = item.setting.detail
return cell
}
)
}
}

@ -0,0 +1,77 @@
//
// CacheViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class CacheViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
}
let itemSelected = PublishSubject<Setting>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let phone = Setting.init(title: "手机号", detail: "去绑定", arrowIcon: "setting_arrow")
let wechatBinding = Setting.init(title: "绑定微信", detail: "", arrowIcon: "setting_arrow")
let privacy = Setting.init(title: "注销账户", detail: "", arrowIcon: "setting_arrow")
//TODO
items.accept([SettingSection.init(items: [.setting(phone), .setting(wechatBinding), .setting(privacy)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
switch sectionItem {
case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
// case .timing(let setting):
// case .cache(let setting):
// case .permission(let setting):
// case .feedback(let setting):
// case .about(let setting):
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
}.disposed(by: rx.disposeBag)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

@ -12,6 +12,7 @@ class EditInfoHeaderView: UIView {
let avatorView = UIImageView.init()
avatorView.layer.cornerRadius = 45
avatorView.layer.masksToBounds = true
avatorView.backgroundColor = .red
return avatorView
}()

@ -25,9 +25,13 @@ class EditInfoViewController: TableViewController {
override func makeUI() {
super.makeUI()
view.backgroundColor = .blue
view.backgroundColor = .white
navigationItem.title = "编辑资料"
tableView.register(MineViewCell.self, forCellReuseIdentifier: "SettingViewCell")
tableView.mj_footer = nil
tableView.mj_header = nil
tableView.register(SettingViewCell.self, forCellReuseIdentifier: "SettingViewCell")
tableView.tableHeaderView = headerView
}
@ -37,36 +41,44 @@ class EditInfoViewController: TableViewController {
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? MineViewModel else { return }
guard let viewModel = viewModel as? EditInfoViewModel else { return }
let input = MineViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
let input = EditInfoViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = MineViewController.dataSource()
let dataSource = EditInfoViewController.dataSource()
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
}.disposed(by: rx.disposeBag)
output.selection.drive { sectionItem in
let accountViewModel = AccountViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .account(viewModel: accountViewModel), sender: self)
}.disposed(by: rx.disposeBag)
}
}
extension EditInfoViewController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<MineSection> {
return RxTableViewSectionedReloadDataSource<MineSection>(
static func dataSource() -> RxTableViewSectionedReloadDataSource<SettingSection> {
return RxTableViewSectionedReloadDataSource<SettingSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: MineViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! MineViewCell
let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell
cell.titleLabel.text = "123"
cell.detailLabel.text = "321"
cell.titleLabel.text = item.setting.title
cell.detailLabel.text = item.setting.detail
return cell
}

@ -77,3 +77,4 @@ class EditInfoViewModel: ViewModel, ViewModelType {
}

@ -7,22 +7,32 @@
import UIKit
class EditNameController: ViewController {
let editNameTextField: EditNameTextField = {
let editNameTextField = EditNameTextField.init(frame: CGRect.init(x: 0, y: 0, width: BaseDimensions.screenWidth, height: 52))
return editNameTextField
class EditNameController: UIViewController {
let editNameTextFieldView: EditNameTextFieldView = {
let editNameTextFieldView = EditNameTextFieldView.init(frame: CGRect.init(x: 0, y: 0, width: BaseDimensions.screenWidth, height: 52))
return editNameTextFieldView
}()
lazy var confirmBarButton: BarButtonItem = {
let confirmBarButton = BarButtonItem.init(title: "提交", style: .plain, target: self, action: nil)
return confirmBarButton
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
makeUI()
}
override func makeUI() {
super.makeUI()
func makeUI() {
navigationItem.title = "设置用户名"
view.backgroundColor = .white
view.addSubview(editNameTextFieldView)
view.addSubview(editNameTextField)
self.navigationItem.rightBarButtonItem = confirmBarButton
}
@ -31,9 +41,10 @@ class EditNameController: ViewController {
}
class EditNameTextField: UIView {
class EditNameTextFieldView: UIView {
let textFieldView: UITextField = {
let textFieldView = UITextField.init()
textFieldView.placeholder = "修改用户名"
return textFieldView
}()
@ -42,11 +53,17 @@ class EditNameTextField: UIView {
let countTipsLabel = UILabel.init()
countTipsLabel.font = UIFont.systemFont(ofSize: 15)
countTipsLabel.text = "4/12"
return countTipsLabel
}()
let lineView: UIView = {
let lineView = UIView.init()
lineView.backgroundColor = .separator()
return lineView
}()
override init(frame: CGRect) {
super.init(frame: frame)
makeUI()
@ -59,6 +76,7 @@ class EditNameTextField: UIView {
func makeUI() {
addSubview(textFieldView)
addSubview(countTipsLabel)
addSubview(lineView)
}
@ -68,6 +86,7 @@ class EditNameTextField: UIView {
countTipsLabel.snp.makeConstraints { make in
make.right.equalTo(self).offset(-18)
make.centerY.equalTo(self)
make.width.equalTo(35)
}
@ -76,5 +95,11 @@ class EditNameTextField: UIView {
make.right.equalTo(countTipsLabel.snp.left).offset(-18)
make.centerY.equalTo(self)
}
lineView.snp.makeConstraints { make in
make.bottom.equalTo(self)
make.height.equalTo(1)
make.left.equalTo(self).offset(18)
make.right.equalTo(self).offset(-18)
}
}
}

@ -7,7 +7,7 @@
import UIKit
class FeedbackViewController: ViewController {
class FeedbackViewController: UIViewController {
let feedbackTypeView: FeedbackTypeView = {
let feedbackTypeView = FeedbackTypeView.init()
@ -39,12 +39,11 @@ class FeedbackViewController: ViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
makeUI()
}
override func makeUI() {
super.makeUI()
func makeUI() {
view.addSubview(feedbackTypeView)
view.addSubview(feedbackDetailView)

@ -6,18 +6,85 @@
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class PrivacyViewController: TableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func makeUI() {
super.makeUI()
navigationItem.title = "消息和隐私设置"
self.tableView.mj_header = nil
self.tableView.mj_footer = nil
tableView.register(SettingViewCell.self, forCellReuseIdentifier: "SettingViewCell")
view.backgroundColor = .white
}
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? PrivacyViewModel else { return }
let input = PrivacyViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = PrivacyViewController.dataSource()
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
}.disposed(by: rx.disposeBag)
output.selection.drive { sectionItem in
let accountViewModel = AccountViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .account(viewModel: accountViewModel), sender: self)
}.disposed(by: rx.disposeBag)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
}
extension PrivacyViewController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<SettingSection> {
return RxTableViewSectionedReloadDataSource<SettingSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell
cell.titleLabel.text = item.setting.title
cell.detailLabel.text = item.setting.detail
return cell
}
)
}
}

@ -0,0 +1,78 @@
//
// PrivacyViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class PrivacyViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
}
let itemSelected = PublishSubject<Setting>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let like = Setting.init(title: "点赞通知", detail: "", arrowIcon: "setting_arrow")
let follower = Setting.init(title: "新增关注通知", detail: "", arrowIcon: "setting_arrow")
let privateMessages = Setting.init(title: "私信", detail: "", arrowIcon: "setting_arrow")
let push = Setting.init(title: "系统推送", detail: "", arrowIcon: "setting_arrow")
//TODO
items.accept([SettingSection.init(items: [.setting(like), .setting(follower), .setting(privateMessages), .setting(push)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
switch sectionItem {
case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
// case .timing(let setting):
// case .cache(let setting):
// case .permission(let setting):
// case .feedback(let setting):
// case .about(let setting):
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
}.disposed(by: rx.disposeBag)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

@ -37,9 +37,21 @@ class SettingViewCell: UITableViewCell {
return switchButton
}()
var setting: Setting? {
didSet {
titleLabel.text = setting?.title
detailLabel.text = setting?.detail
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
makeUI()
}
required init?(coder: NSCoder) {
@ -90,6 +102,7 @@ class SettingViewFooterView: UIView {
let logoutButton = UIButton.init()
logoutButton.titleLabel?.font = UIFont.systemFont(ofSize: 15)
logoutButton.setTitle("退出登录", for: .normal)
logoutButton.setTitleColor(.primary(), for: .normal)
return logoutButton
}()
@ -99,6 +112,7 @@ class SettingViewFooterView: UIView {
super.init(frame: frame)
addSubview(logoutButton)
backgroundColor = .white
logoutButton.snp.makeConstraints { make in
make.edges.equalTo(self)

@ -26,9 +26,9 @@ class SettingViewController: TableViewController {
override func makeUI() {
super.makeUI()
view.backgroundColor = .blue
view.backgroundColor = .init(hex: 0xf5f5f5)
tableView.register(MineViewCell.self, forCellReuseIdentifier: "SettingViewCell")
tableView.register(SettingViewCell.self, forCellReuseIdentifier: "SettingViewCell")
tableView.tableFooterView = footerView
}
@ -38,18 +38,84 @@ class SettingViewController: TableViewController {
override func bindViewModel() {
super.bindViewModel()
guard let viewModel = viewModel as? MineViewModel else { return }
guard let viewModel = viewModel as? SettingViewMdel else { return }
let input = MineViewModel.Input.init(viewWillAppear: rx.viewWillAppear,
let input = SettingViewMdel.Input.init(viewWillAppear: rx.viewWillAppear,
selection: tableView.rx.itemSelected.asDriver())
let output = viewModel.transform(input: input)
let dataSource = MineViewController.dataSource()
let dataSource = SettingViewController.dataSource()
output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)
output.itemSelected.subscribe { sectionItem in
guard let sectionItem = sectionItem.element else { return }
switch sectionItem {
case .editInfo(let setting):
let editInfo = EditInfoViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .editInfo(viewModel: editInfo), sender: self)
case .account(let setting):
let accountViewModel = AccountViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .account(viewModel: accountViewModel), sender: self)
case .privacy(let setting):
let privacyViewModel = PrivacyViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .privacy(viewModel: privacyViewModel), sender: self)
case .timing(let setting):
let timingViewModel = TimingViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .timing(viewModel: timingViewModel), sender: self)
case .cache(let setting):
let cacheViewModel = CacheViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .cache(viewModel: cacheViewModel), sender: self)
case .permission(let setting):
let accountViewModel = AccountViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .account(viewModel: accountViewModel), sender: self)
case .feedback(let setting):
// let accountViewModel = Feedbackview.init(provider: viewModel.provider)
self.navigator.show(segue: .feedback, sender: self)
case .about(let setting):
let aboutViewModel = AboutViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .about(viewModel: aboutViewModel), sender: self)
case .contributors(let setting):
let thanksViewModel = ThanksViewModel.init(provider: viewModel.provider)
self.navigator.show(segue: .thanks(viewModel: thanksViewModel), sender: self)
case .version(let setting):
break
case .setting(_):
break
}
// let editInfoViewModel = EditInfoViewModel.init(provider: viewModel.provider)
//
// self.navigator.show(segue: .editInfo(viewModel: editInfoViewModel), sender: self)
}.disposed(by: rx.disposeBag)
output.selection.drive { sectionItem in
// let editInfoViewModel = EditInfoViewModel.init(provider: viewModel.provider)
//
// self.navigator.show(segue: .editInfo(viewModel: editInfoViewModel), sender: self)
// let thanksViewModel = ThanksViewModel.init(provider: viewModel.provider)
//
// self.navigator.show(segue: .thanks(viewModel: thanksViewModel), sender: self)
}.disposed(by: rx.disposeBag)
@ -61,13 +127,12 @@ class SettingViewController: TableViewController {
extension SettingViewController {
static func dataSource() -> RxTableViewSectionedReloadDataSource<MineSection> {
return RxTableViewSectionedReloadDataSource<MineSection>(
static func dataSource() -> RxTableViewSectionedReloadDataSource<SettingSection> {
return RxTableViewSectionedReloadDataSource<SettingSection>(
configureCell: { dataSource, tableView, indexPath, item in
let cell: MineViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! MineViewCell
let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell
cell.titleLabel.text = "123"
cell.detailLabel.text = "321"
cell.setting = item.setting
return cell
}

@ -22,11 +22,11 @@ class SettingViewMdel: ViewModel, ViewModelType {
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
let itemSelected: PublishSubject<SettingType>
}
let itemSelected = PublishSubject<Setting>()
let itemSelected = PublishSubject<SettingType>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
@ -51,15 +51,17 @@ class SettingViewMdel: ViewModel, ViewModelType {
let version = Setting.init(title: "检查版本", detail: "", arrowIcon: "setting_arrow")
items.accept([SettingSection.init(items: [.editInfo(editInfo), .account(account), .privacy(privacy)])])
items.accept([SettingSection.init(items: [.editInfo(editInfo), .account(account), .privacy(privacy), .timing(timing), .cache(cache), .privacy(privacy), .feedback(feedback), .about(about), .contributors(contributors), .version(version)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
self.itemSelected.onNext(sectionItem)
switch sectionItem {
case .about(let setting):
// switch sectionItem {
// case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
@ -71,11 +73,10 @@ class SettingViewMdel: ViewModel, ViewModelType {
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
// default: break
//
// }
}.disposed(by: rx.disposeBag)

@ -0,0 +1,77 @@
//
// ThanksViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class ThanksViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
}
let itemSelected = PublishSubject<Setting>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let phone = Setting.init(title: "手机号", detail: "去绑定", arrowIcon: "setting_arrow")
let wechatBinding = Setting.init(title: "绑定微信", detail: "", arrowIcon: "setting_arrow")
let privacy = Setting.init(title: "注销账户", detail: "", arrowIcon: "setting_arrow")
//TODO
items.accept([SettingSection.init(items: [.setting(phone), .setting(wechatBinding), .setting(privacy)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
switch sectionItem {
case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
// case .timing(let setting):
// case .cache(let setting):
// case .permission(let setting):
// case .feedback(let setting):
// case .about(let setting):
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
}.disposed(by: rx.disposeBag)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

@ -0,0 +1,77 @@
//
// TimingViewModel.swift
// IndieMusic
//
// Created by WenLei on 2024/1/7.
//
import Foundation
import RxSwift
import RxCocoa
class TimingViewModel: ViewModel, ViewModelType {
struct Input {
let viewWillAppear: ControlEvent<Bool>
let selection: Driver<IndexPath>
}
struct Output {
let items: BehaviorRelay<[SettingSection]>
let selection: Driver<IndexPath>
let itemSelected: PublishSubject<Setting>
}
let itemSelected = PublishSubject<Setting>()
let items = BehaviorRelay<[SettingSection]>.init(value: [])
func transform(input: Input) -> Output {
input.viewWillAppear.subscribe { (_) in
}.disposed(by: rx.disposeBag)
let phone = Setting.init(title: "手机号", detail: "去绑定", arrowIcon: "setting_arrow")
let wechatBinding = Setting.init(title: "绑定微信", detail: "", arrowIcon: "setting_arrow")
let privacy = Setting.init(title: "注销账户", detail: "", arrowIcon: "setting_arrow")
//TODO
items.accept([SettingSection.init(items: [.setting(phone), .setting(wechatBinding), .setting(privacy)])])
input.selection.drive { indexPath in
guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return }
switch sectionItem {
case .about(let setting):
// case .account(let setting):
// case .privacy(let setting):
// case .timing(let setting):
// case .cache(let setting):
// case .permission(let setting):
// case .feedback(let setting):
// case .about(let setting):
// case .contributors(let setting):
// case .version(let setting):
self.itemSelected.onNext(setting)
default: break
}
}.disposed(by: rx.disposeBag)
return Output.init(items: items,
selection: input.selection,
itemSelected: itemSelected)
}
}

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

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#B44343"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.3791 11.5642C15.7189 11.7553 15.7189 12.2446 15.3791 12.4358L9.51432 15.7347C9.18102 15.9222 8.76919 15.6813 8.76919 15.2989L8.76919 8.70106C8.76919 8.31864 9.18102 8.07778 9.51432 8.26527L15.3791 11.5642Z" fill="white" fill-opacity="0.95"/>
</svg>

After

Width:  |  Height:  |  Size: 446 B

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

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 7.49999L12.927 12.63C12.6491 12.8041 12.3279 12.8964 12 12.8964C11.6721 12.8964 11.3509 12.8041 11.073 12.63L3 7.49999M4.8 4.79999H19.2C20.1941 4.79999 21 5.60588 21 6.59999V17.4C21 18.3941 20.1941 19.2 19.2 19.2H4.8C3.80589 19.2 3 18.3941 3 17.4V6.59999C3 5.60588 3.80589 4.79999 4.8 4.79999Z" stroke="#17171A" stroke-width="1.35" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 497 B

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

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.4659 3.17438C11.7964 2.98357 12.2036 2.98357 12.5341 3.17438L19.3762 7.12466C19.7067 7.31547 19.9103 7.6681 19.9103 8.04973V15.9503C19.9103 16.3319 19.7067 16.6845 19.3762 16.8753L12.5341 20.8256C12.2036 21.0164 11.7964 21.0164 11.4659 20.8256L4.62384 16.8753C4.29334 16.6845 4.08975 16.3319 4.08975 15.9503V8.04973C4.08975 7.6681 4.29334 7.31547 4.62384 7.12466L11.4659 3.17438Z" fill="white" fill-opacity="0.95" stroke="#17171A" stroke-width="1.5"/>
<circle cx="12" cy="12" r="3.25" stroke="#17171A" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 639 B

Loading…
Cancel
Save