diff --git a/IndieMusic/IndieMusic.xcodeproj/project.pbxproj b/IndieMusic/IndieMusic.xcodeproj/project.pbxproj index 40e9903..ce431c6 100644 --- a/IndieMusic/IndieMusic.xcodeproj/project.pbxproj +++ b/IndieMusic/IndieMusic.xcodeproj/project.pbxproj @@ -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 = ""; }; 778B8AB92AF8ED280034AFD4 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 778B8ABA2AF8ED280034AFD4 /* TabViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabViewController.swift; sourceTree = ""; }; + 77C9B9BD2B4AB4FA0006C83F /* TimingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimingViewModel.swift; sourceTree = ""; }; + 77C9B9BF2B4AB5B50006C83F /* PrivacyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyViewModel.swift; sourceTree = ""; }; + 77C9B9C12B4AB6C10006C83F /* AboutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewModel.swift; sourceTree = ""; }; + 77C9B9C32B4AB75E0006C83F /* CacheViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheViewModel.swift; sourceTree = ""; }; 77FA0B272B0B3E1E00404C5E /* Journal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Journal.swift; sourceTree = ""; }; 77FA0B292B0B5F0D00404C5E /* AudioMoreActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMoreActionView.swift; sourceTree = ""; }; 77FA0B2B2B0C480B00404C5E /* AudioMoreActionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioMoreActionViewModel.swift; sourceTree = ""; }; @@ -302,6 +315,11 @@ 77FB7A6F2B48074600B64030 /* MusicStyleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicStyleViewModel.swift; sourceTree = ""; }; 77FB7A712B48E93100B64030 /* SearchResultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewModel.swift; sourceTree = ""; }; 77FB7A732B49944E00B64030 /* ScrollSegmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollSegmentView.swift; sourceTree = ""; }; + 77FB7A752B4A4B5600B64030 /* MineJournalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineJournalViewController.swift; sourceTree = ""; }; + 77FB7A772B4A4B6400B64030 /* MineJournalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineJournalViewModel.swift; sourceTree = ""; }; + 77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewController.swift; sourceTree = ""; }; + 77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = ""; }; + 77FB7A7E2B4A630100B64030 /* ThanksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThanksViewModel.swift; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; 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 = ""; }; @@ -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 = ""; @@ -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 = ""; @@ -680,6 +706,15 @@ path = "RxSwift+Extension"; sourceTree = ""; }; + 77FB7A792B4A4FB600B64030 /* Message */ = { + isa = PBXGroup; + children = ( + 77FB7A7A2B4A4FC900B64030 /* MessageViewController.swift */, + 77FB7A7C2B4A4FD400B64030 /* MessageViewModel.swift */, + ); + path = Message; + sourceTree = ""; + }; 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; diff --git a/IndieMusic/IndieMusic/Application/Navigator.swift b/IndieMusic/IndieMusic/Application/Navigator.swift index 3313f2d..0cb481f 100644 --- a/IndieMusic/IndieMusic/Application/Navigator.swift +++ b/IndieMusic/IndieMusic/Application/Navigator.swift @@ -26,7 +26,20 @@ 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) case test @@ -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 + } } diff --git a/IndieMusic/IndieMusic/Common/ScrollSegmentView.swift b/IndieMusic/IndieMusic/Common/ScrollSegmentView.swift index d5d00c9..31c15dd 100644 --- a/IndieMusic/IndieMusic/Common/ScrollSegmentView.swift +++ b/IndieMusic/IndieMusic/Common/ScrollSegmentView.swift @@ -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 diff --git a/IndieMusic/IndieMusic/Common/ViewController.swift b/IndieMusic/IndieMusic/Common/ViewController.swift index 6c60010..dc7e99e 100644 --- a/IndieMusic/IndieMusic/Common/ViewController.swift +++ b/IndieMusic/IndieMusic/Common/ViewController.swift @@ -52,7 +52,7 @@ class ViewController: UIViewController, Navigatable { let motionShakeEvent = PublishSubject() 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 }() @@ -85,6 +85,10 @@ class ViewController: UIViewController, Navigatable { closeBarButton.rx.tap.asObservable().subscribe(onNext: { [weak self] () in 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() @@ -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 } diff --git a/IndieMusic/IndieMusic/Models/Mine.swift b/IndieMusic/IndieMusic/Models/Mine.swift index 993204c..cb561c3 100644 --- a/IndieMusic/IndieMusic/Models/Mine.swift +++ b/IndieMusic/IndieMusic/Models/Mine.swift @@ -11,6 +11,7 @@ import RxDataSources struct Mine: Codable { let title: String let detail: String + let isPlaying: Bool } struct MineSection { diff --git a/IndieMusic/IndieMusic/Models/Setting.swift b/IndieMusic/IndieMusic/Models/Setting.swift index 0033510..cde9976 100644 --- a/IndieMusic/IndieMusic/Models/Setting.swift +++ b/IndieMusic/IndieMusic/Models/Setting.swift @@ -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] diff --git a/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift b/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift new file mode 100644 index 0000000..bfce4e2 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Message/MessageViewController.swift @@ -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. + } + + +} diff --git a/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift b/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift new file mode 100644 index 0000000..66b959b --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Message/MessageViewModel.swift @@ -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 + let selection: Driver + + let dropButtonTrigger: Driver + let playButtonTrigger: Driver + let shareButtonTrigger: Driver +// let moreButtonTrigger: Driver + + } + + struct Output { + let items: BehaviorRelay<[JournalSection]> + let selection: Driver + let itemSelected: PublishSubject + + let journalDetail: PublishSubject + + let currentPlaying: PublishSubject + let dowloadState: Driver + let isLike: BehaviorRelay + let isExpand: BehaviorRelay + } + + let itemSelected = PublishSubject() + let items = BehaviorRelay<[JournalSection]>.init(value: []) + + let isExpand = BehaviorRelay.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.init() + + let currentPlaying: PublishSubject = .init() + let dowloadState: Driver = .just(0) + let isLike = BehaviorRelay.init(value: false) + + let isLick = BehaviorRelay.init(value: false) + + return Output.init(items: items, + selection: input.selection, + itemSelected: itemSelected, + journalDetail: journal, + currentPlaying: currentPlaying, + dowloadState: dowloadState, + isLike: isLike, + isExpand: isExpand + ) + } + +} + diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewController.swift b/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewController.swift new file mode 100644 index 0000000..5a0d480 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewController.swift @@ -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 { + return RxCollectionViewSectionedReloadDataSource( + 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 + } + ) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewModel.swift b/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewModel.swift new file mode 100644 index 0000000..1c08cf6 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Mine/MineJournalViewModel.swift @@ -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 + let selection: Driver + } + + struct Output { + let items: BehaviorRelay<[MusicStyleSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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.init() + + + return Output.init(items: items, + selection: input.selection, + itemSelected: itemSelected + ) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineSingleController.swift b/IndieMusic/IndieMusic/Modules/Mine/MineSingleController.swift index ea08efb..0a7adbb 100644 --- a/IndieMusic/IndieMusic/Modules/Mine/MineSingleController.swift +++ b/IndieMusic/IndieMusic/Modules/Mine/MineSingleController.swift @@ -10,8 +10,14 @@ 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 { - static func dataSource() -> RxTableViewSectionedReloadDataSource { + 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(_ buttonTapHandler: @escaping (UITableViewCell, AudioTrack) -> Void) -> RxTableViewSectionedReloadDataSource { return RxTableViewSectionedReloadDataSource( 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.audioTrack = it + -// cell.titleLabel.text = "123" -// cell.detailLabel.text = "321" + 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) + } + } +} diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineView.swift b/IndieMusic/IndieMusic/Modules/Mine/MineView.swift index 626cf90..05bbe9f 100644 --- a/IndieMusic/IndieMusic/Modules/Mine/MineView.swift +++ b/IndieMusic/IndieMusic/Modules/Mine/MineView.swift @@ -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 { } } + diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift b/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift index 826afa6..adf8d48 100644 --- a/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Mine/MineViewController.swift @@ -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,9 +97,33 @@ 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 } diff --git a/IndieMusic/IndieMusic/Modules/Mine/MineViewModel.swift b/IndieMusic/IndieMusic/Modules/Mine/MineViewModel.swift index 9804253..b9551f8 100644 --- a/IndieMusic/IndieMusic/Modules/Mine/MineViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Mine/MineViewModel.swift @@ -22,6 +22,7 @@ class MineViewModel: ViewModel, ViewModelType { let items: BehaviorRelay<[MineSection]> let selection: Driver let itemSelected: PublishSubject + } @@ -34,9 +35,11 @@ class MineViewModel: ViewModel, ViewModelType { }.disposed(by: rx.disposeBag) - let mine = Mine.init(title: "ttt", detail: "123") - - items.accept([MineSection.init(items: [mine, mine, mine])]) + 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: [single, journal, download])]) input.selection.drive { indexPath in diff --git a/IndieMusic/IndieMusic/Modules/Search/SearchResultsController.swift b/IndieMusic/IndieMusic/Modules/Search/SearchResultsController.swift index 92266f3..8592792 100644 --- a/IndieMusic/IndieMusic/Modules/Search/SearchResultsController.swift +++ b/IndieMusic/IndieMusic/Modules/Search/SearchResultsController.swift @@ -28,13 +28,13 @@ 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 { + return RxTableViewSectionedReloadDataSource( + 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 { + return RxCollectionViewSectionedReloadDataSource( + 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 { - return RxCollectionViewSectionedReloadDataSource( - 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 { - return RxTableViewSectionedReloadDataSource( - configureCell: { dataSource, tableView, indexPath, item in - let cell: SongViewCell = tableView.dequeueReusableCell(withIdentifier: "SongViewCell", for: indexPath) as! SongViewCell - - cell.audioTrack = item - - return cell - } - ) - } -} diff --git a/IndieMusic/IndieMusic/Modules/Search/SearchResultsViewModel.swift b/IndieMusic/IndieMusic/Modules/Search/SearchResultsViewModel.swift index 394886d..1dc623c 100644 --- a/IndieMusic/IndieMusic/Modules/Search/SearchResultsViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Search/SearchResultsViewModel.swift @@ -14,39 +14,60 @@ class SearchResultsViewModel: ViewModel, ViewModelType { struct Input { let viewWillAppear: ControlEvent - let selection: Driver + let closeButtonTrigger: Driver + let collectionViewSelection: Driver + } struct Output { - let items: BehaviorRelay<[SearchSection]> - let selection: Driver - let itemSelected: PublishSubject - + let tableViewItems: BehaviorRelay<[JournalSection]> + let collectionViewItems: BehaviorRelay<[MusicStyleSection]> + + let collectionViewItemSelected: PublishSubject } - let itemSelected = PublishSubject() - let items = BehaviorRelay<[SearchSection]>.init(value: []) + let tableViewItems = BehaviorRelay<[JournalSection]>.init(value: []) + let collectionViewItemstems = BehaviorRelay<[MusicStyleSection]>.init(value: []) + let collectionViewSelection = PublishSubject() + 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) + + tableViewItems.accept([journalSection]) + + + + 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]) - items.accept([searchSection]) - input.selection.drive { indexPath in - guard let sectionItem = self.items.value.first?.items[indexPath.row] else { return } - self.itemSelected.onNext(sectionItem) + 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) + } } diff --git a/IndieMusic/IndieMusic/Modules/Setting/AboutViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/AboutViewController.swift index e6c1348..9278157 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/AboutViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/AboutViewController.swift @@ -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 { - return RxTableViewSectionedReloadDataSource( + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( 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) } } diff --git a/IndieMusic/IndieMusic/Modules/Setting/AboutViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/AboutViewModel.swift new file mode 100644 index 0000000..87f780d --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Setting/AboutViewModel.swift @@ -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 + let selection: Driver + + } + + struct Output { + let items: BehaviorRelay<[SettingSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Setting/AccountViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/AccountViewController.swift index 548f979..a1c0606 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/AccountViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/AccountViewController.swift @@ -6,6 +6,9 @@ // import UIKit +import RxSwift +import RxCocoa +import RxDataSources class AccountViewController: TableViewController { @@ -15,5 +18,73 @@ class AccountViewController: TableViewController { // 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? 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 { + return RxTableViewSectionedReloadDataSource( + 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 + } + ) + } +} diff --git a/IndieMusic/IndieMusic/Modules/Setting/CacheViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/CacheViewModel.swift new file mode 100644 index 0000000..cb4a1ea --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Setting/CacheViewModel.swift @@ -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 + let selection: Driver + + } + + struct Output { + let items: BehaviorRelay<[SettingSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Setting/EditInfoView.swift b/IndieMusic/IndieMusic/Modules/Setting/EditInfoView.swift index bc9d674..66396ba 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/EditInfoView.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/EditInfoView.swift @@ -12,6 +12,7 @@ class EditInfoHeaderView: UIView { let avatorView = UIImageView.init() avatorView.layer.cornerRadius = 45 avatorView.layer.masksToBounds = true + avatorView.backgroundColor = .red return avatorView }() diff --git a/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewController.swift index 6278561..828f485 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewController.swift @@ -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 { - return RxTableViewSectionedReloadDataSource( + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( 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 } diff --git a/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewModel.swift index b5807b3..8e6a453 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewModel.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/EditInfoViewModel.swift @@ -77,3 +77,4 @@ class EditInfoViewModel: ViewModel, ViewModelType { } + diff --git a/IndieMusic/IndieMusic/Modules/Setting/EditNameController.swift b/IndieMusic/IndieMusic/Modules/Setting/EditNameController.swift index 42eaadd..3adf4d4 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/EditNameController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/EditNameController.swift @@ -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) + } } } diff --git a/IndieMusic/IndieMusic/Modules/Setting/FeedbackViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/FeedbackViewController.swift index f6b2404..81ade47 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/FeedbackViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/FeedbackViewController.swift @@ -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) diff --git a/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewController.swift index f7560eb..4b42301 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewController.swift @@ -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 { + return RxTableViewSectionedReloadDataSource( + 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 + } + ) } } diff --git a/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewModel.swift new file mode 100644 index 0000000..a20c10b --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Setting/PrivacyViewModel.swift @@ -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 + let selection: Driver + + } + + struct Output { + let items: BehaviorRelay<[SettingSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Setting/SettingView.swift b/IndieMusic/IndieMusic/Modules/Setting/SettingView.swift index 4ae41bd..bef7e45 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/SettingView.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/SettingView.swift @@ -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) diff --git a/IndieMusic/IndieMusic/Modules/Setting/SettingViewController.swift b/IndieMusic/IndieMusic/Modules/Setting/SettingViewController.swift index f97449f..0e74c04 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/SettingViewController.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/SettingViewController.swift @@ -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,20 +38,86 @@ 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,14 +127,13 @@ class SettingViewController: TableViewController { extension SettingViewController { - static func dataSource() -> RxTableViewSectionedReloadDataSource { - return RxTableViewSectionedReloadDataSource( + static func dataSource() -> RxTableViewSectionedReloadDataSource { + return RxTableViewSectionedReloadDataSource( configureCell: { dataSource, tableView, indexPath, item in - let cell: MineViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! MineViewCell - - cell.titleLabel.text = "123" - cell.detailLabel.text = "321" + let cell: SettingViewCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewCell", for: indexPath) as! SettingViewCell + cell.setting = item.setting + return cell } ) diff --git a/IndieMusic/IndieMusic/Modules/Setting/SettingViewMdel.swift b/IndieMusic/IndieMusic/Modules/Setting/SettingViewMdel.swift index 735f02b..a188091 100644 --- a/IndieMusic/IndieMusic/Modules/Setting/SettingViewMdel.swift +++ b/IndieMusic/IndieMusic/Modules/Setting/SettingViewMdel.swift @@ -22,11 +22,11 @@ class SettingViewMdel: ViewModel, ViewModelType { struct Output { let items: BehaviorRelay<[SettingSection]> let selection: Driver - let itemSelected: PublishSubject + let itemSelected: PublishSubject } - let itemSelected = PublishSubject() + let itemSelected = PublishSubject() 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) diff --git a/IndieMusic/IndieMusic/Modules/Setting/ThanksViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/ThanksViewModel.swift new file mode 100644 index 0000000..b8d6a79 --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Setting/ThanksViewModel.swift @@ -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 + let selection: Driver + + } + + struct Output { + let items: BehaviorRelay<[SettingSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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) + } + +} diff --git a/IndieMusic/IndieMusic/Modules/Setting/TimingViewModel.swift b/IndieMusic/IndieMusic/Modules/Setting/TimingViewModel.swift new file mode 100644 index 0000000..717811d --- /dev/null +++ b/IndieMusic/IndieMusic/Modules/Setting/TimingViewModel.swift @@ -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 + let selection: Driver + + } + + struct Output { + let items: BehaviorRelay<[SettingSection]> + let selection: Driver + let itemSelected: PublishSubject + + } + + let itemSelected = PublishSubject() + 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) + } + +} diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/Contents.json b/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/Contents.json new file mode 100644 index 0000000..a70d834 --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/Contents.json @@ -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 + } +} diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/song_playAll_btn.svg b/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/song_playAll_btn.svg new file mode 100644 index 0000000..96926e4 --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/audio/audio_playAll_btn.imageset/song_playAll_btn.svg @@ -0,0 +1,4 @@ + + + + diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/Contents.json b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/Contents.json new file mode 100644 index 0000000..acb1c6e --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/Contents.json @@ -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 + } +} diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/mine_message_btn.svg b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/mine_message_btn.svg new file mode 100644 index 0000000..a6d0ffe --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_message_btn.imageset/mine_message_btn.svg @@ -0,0 +1,3 @@ + + + diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/Contents.json b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/Contents.json new file mode 100644 index 0000000..9a456c4 --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/Contents.json @@ -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 + } +} diff --git a/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/mine_setting_btn.svg b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/mine_setting_btn.svg new file mode 100644 index 0000000..3a0e3c4 --- /dev/null +++ b/IndieMusic/IndieMusic/Resources/Assets.xcassets/setting/mine_setting_btn.imageset/mine_setting_btn.svg @@ -0,0 +1,4 @@ + + + +