diff --git a/StreetDrop/StreetDrop.xcodeproj/project.pbxproj b/StreetDrop/StreetDrop.xcodeproj/project.pbxproj index c0ca834e..11a5f345 100644 --- a/StreetDrop/StreetDrop.xcodeproj/project.pbxproj +++ b/StreetDrop/StreetDrop.xcodeproj/project.pbxproj @@ -150,6 +150,7 @@ 6A51EC402C411FB000DEF6F3 /* MusicListTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */; }; 6A51EC672C48F22600DEF6F3 /* TapListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC662C48F22600DEF6F3 /* TapListView.swift */; }; 6A51EC692C48F53400DEF6F3 /* MusicListFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC682C48F53400DEF6F3 /* MusicListFilterView.swift */; }; + 6A51EC6D2C49F2FA00DEF6F3 /* FilterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC6C2C49F2FA00DEF6F3 /* FilterType.swift */; }; 6A7D73D92BB11A0E009340E3 /* LevelUpGuideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */; }; 6A7D73DD2BB14015009340E3 /* GradientProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */; }; 6A7D73DF2BB15826009340E3 /* UIView+RoundCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7D73DE2BB15826009340E3 /* UIView+RoundCorners.swift */; }; @@ -430,6 +431,7 @@ 6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicListTableView.swift; sourceTree = ""; }; 6A51EC662C48F22600DEF6F3 /* TapListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TapListView.swift; sourceTree = ""; }; 6A51EC682C48F53400DEF6F3 /* MusicListFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicListFilterView.swift; sourceTree = ""; }; + 6A51EC6C2C49F2FA00DEF6F3 /* FilterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterType.swift; sourceTree = ""; }; 6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelUpGuideView.swift; sourceTree = ""; }; 6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientProgressBar.swift; sourceTree = ""; }; 6A7D73DE2BB15826009340E3 /* UIView+RoundCorners.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+RoundCorners.swift"; sourceTree = ""; }; @@ -1096,15 +1098,12 @@ isa = PBXGroup; children = ( 1867C81F2A4DDB8C00F8EC48 /* MyPageViewController.swift */, - 6A51EC662C48F22600DEF6F3 /* TapListView.swift */, - 6A51EC682C48F53400DEF6F3 /* MusicListFilterView.swift */, - 1867C8232A4FFCDF00F8EC48 /* MusicListCell.swift */, 18EF9FC82A5C51FB00266D27 /* NicknameEditViewController.swift */, - 1816ED3B2A680608005009FC /* MusicListSectionHeaderView.swift */, - 0856524F2AFBB73100FD9BCB /* MyPageType.swift */, + 6A51EC6A2C49F29C00DEF6F3 /* TabBar */, + 6A51EC6B2C49F2BA00DEF6F3 /* MusicList */, 6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */, 6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */, - 6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */, + 6A51EC6C2C49F2FA00DEF6F3 /* FilterType.swift */, ); path = View; sourceTree = ""; @@ -1416,6 +1415,26 @@ path = NetworkManagerTest; sourceTree = ""; }; + 6A51EC6A2C49F29C00DEF6F3 /* TabBar */ = { + isa = PBXGroup; + children = ( + 6A51EC662C48F22600DEF6F3 /* TapListView.swift */, + 6A51EC682C48F53400DEF6F3 /* MusicListFilterView.swift */, + ); + path = TabBar; + sourceTree = ""; + }; + 6A51EC6B2C49F2BA00DEF6F3 /* MusicList */ = { + isa = PBXGroup; + children = ( + 6A51EC3F2C411FB000DEF6F3 /* MusicListTableView.swift */, + 1867C8232A4FFCDF00F8EC48 /* MusicListCell.swift */, + 1816ED3B2A680608005009FC /* MusicListSectionHeaderView.swift */, + 0856524F2AFBB73100FD9BCB /* MyPageType.swift */, + ); + path = MusicList; + sourceTree = ""; + }; 9AF428BDAA5509AEF1F4FB64 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -2027,6 +2046,7 @@ C4D16FCC2A1B98B0008B076F /* UILabel+LineHeight.swift in Sources */, 1876F04A2A66EDF10064B887 /* MyMusic.swift in Sources */, C419724A2ABDC94A00211222 /* DefaultDeletingMusicUseCase.swift in Sources */, + 6A51EC6D2C49F2FA00DEF6F3 /* FilterType.swift in Sources */, C41972462ABDC45000211222 /* DefaultClaimingCommentUseCase.swift in Sources */, C45A4CB02A3710AC00EE9C36 /* ImageCacheError.swift in Sources */, 08F5745D2C46992500635B54 /* DefaultFetchingMyLevelUseCase.swift in Sources */, diff --git a/StreetDrop/StreetDrop/Domain/Entity/ModalOption.swift b/StreetDrop/StreetDrop/Domain/Entity/ModalOption.swift index 79d85dd7..508328a7 100644 --- a/StreetDrop/StreetDrop/Domain/Entity/ModalOption.swift +++ b/StreetDrop/StreetDrop/Domain/Entity/ModalOption.swift @@ -11,4 +11,5 @@ struct ModalOption { let icon: UIImage? let title: String let acton: UIAction + var isSelected: Bool = false } diff --git a/StreetDrop/StreetDrop/Presentation/CommunityView/View/CommunityViewController.swift b/StreetDrop/StreetDrop/Presentation/CommunityView/View/CommunityViewController.swift index 67c6aa44..bb7d31d9 100644 --- a/StreetDrop/StreetDrop/Presentation/CommunityView/View/CommunityViewController.swift +++ b/StreetDrop/StreetDrop/Presentation/CommunityView/View/CommunityViewController.swift @@ -870,6 +870,7 @@ private extension CommunityViewController { ) let modalView = OptionModalViewController( + type: .music, firstOption: shareOption, secondOption: claimOption, thirdOption: blockOption @@ -924,6 +925,7 @@ private extension CommunityViewController { ) let modalView = OptionModalViewController( + type: .music, firstOption: shareOption, secondOption: claimOption, thirdOption: blockOption diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift new file mode 100644 index 00000000..252a7075 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift @@ -0,0 +1,25 @@ +// +// FilterType.swift +// StreetDrop +// +// Created by thoonk on 7/19/24. +// + +import Foundation + +enum FilterType { + case newest + case oldest + case mostPopular + + var title: String { + switch self { + case .newest: + return "최신순" + case .oldest: + return "오래된순" + case .mostPopular: + return "인기순" + } + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListCell.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListCell.swift similarity index 100% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListCell.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListCell.swift diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListSectionHeaderView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListSectionHeaderView.swift similarity index 100% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListSectionHeaderView.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListSectionHeaderView.swift diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListTableView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListTableView.swift similarity index 100% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListTableView.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListTableView.swift diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageType.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MyPageType.swift similarity index 100% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageType.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MyPageType.swift diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift index 320a2ec7..faa6578b 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift @@ -28,6 +28,7 @@ final class MyPageViewController: UIViewController, Toastable, Alertable { private let selectedMusicEvent = PublishRelay() private let disposeBag = DisposeBag() private let totalMusicsCountRelay: ReplayRelay = .create(bufferSize: 1) + private let selectedFilterType: BehaviorRelay = .init(value: .newest) // MARK: - Init @@ -399,6 +400,7 @@ private extension MyPageViewController { .disposed(by: disposeBag) bindTapButtonAction(in: tapListView) + bindFilterButtonAction(in: musicListFilterView) return tabBarView } @@ -444,7 +446,25 @@ private extension MyPageViewController { owner.updateScrollOffset() } .disposed(by: disposeBag) - + } + + func bindFilterButtonAction(in musicListFilterView: MusicListFilterView) { + musicListFilterView.rx.onSortFilterTap + .withLatestFrom(selectedFilterType) + .bind(with: self) { owner, type in + owner.showFilteringOptionsModal(with: type) + } + .disposed(by: disposeBag) + + musicListFilterView.rx.onRegionFilterTap + .bind(with: self) { owner, _ in + + } + .disposed(by: disposeBag) + + selectedFilterType + .bind(to: musicListFilterView.rx.setSortButtonText) + .disposed(by: disposeBag) } func bindAction() { @@ -645,7 +665,7 @@ private extension MyPageViewController { } } -// MARK: - UICollectionView Methods +// MARK: - Private Methods private extension MyPageViewController { func configureMusicDataSource() -> MusicDataSource { @@ -671,6 +691,51 @@ private extension MyPageViewController { musicDataSource.apply(snapshot, animatingDifferences: true) } + + func showFilteringOptionsModal(with selectedType: FilterType) { + let newestOption = ModalOption( + icon: UIImage(named: "icon-selected"), + title: FilterType.newest.title, + acton: filterMusicList(by: .newest), + isSelected: selectedType == .newest + ) + + let oldestOption = ModalOption( + icon: UIImage(named: "icon-selected"), + title: FilterType.oldest.title, + acton: filterMusicList(by: .oldest), + isSelected: selectedType == .oldest + ) + + let mostPopularOption = ModalOption( + icon: UIImage(named: "icon-selected"), + title: FilterType.mostPopular.title, + acton: filterMusicList(by: .mostPopular), + isSelected: selectedType == .mostPopular + ) + + let modalView = OptionModalViewController( + type: .filterMusicList, + firstOption: newestOption, + secondOption: oldestOption, + thirdOption: mostPopularOption + ) + + modalView.modalPresentationStyle = .overCurrentContext + self.navigationController?.present(modalView, animated: true) + } + + func filterMusicList(by type: FilterType) -> UIAction { + return UIAction { [weak self] _ in + self?.selectedFilterType.accept(type) + self?.navigationController?.dismiss(animated: true) + + /* + TODO: + - API 개발후 작업 예정 + */ + } + } } // MARK: - UITableViewDelegate diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListFilterView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift similarity index 91% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListFilterView.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift index f6577069..7872b22f 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListFilterView.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift @@ -26,6 +26,7 @@ final class MusicListFilterView: UIView { button.titleLabel?.font = .pretendard(size: 14, weightName: .regular) button.setImage(UIImage(named: "icon-arrow-down"), for: .normal) button.semanticContentAttribute = .forceRightToLeft +// button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -10) return button }() @@ -89,6 +90,12 @@ extension Reactive where Base: MusicListFilterView { } } + var setSortButtonText: Binder { + Binder(base) { base, type in + base.sortFilterButton.setTitle(type.title, for: .normal) + } + } + var onSortFilterTap: Observable { base.sortFilterButton.rx.tap.mapVoid() .throttle(.seconds(2), scheduler: MainScheduler.instance) diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/TapListView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/TapListView.swift similarity index 100% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/TapListView.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/TapListView.swift diff --git a/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift b/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift index 43860cef..212bb0f5 100644 --- a/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift +++ b/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift @@ -11,15 +11,23 @@ import SnapKit import RxSwift import RxRelay +enum OptionModalType { + case music + case filterMusicList +} + final class OptionModalViewController: UIViewController { - //MARK: - Life Cycle + private let type: OptionModalType init( + type: OptionModalType, firstOption: ModalOption, secondOption: ModalOption, thirdOption: ModalOption ) { + self.type = type + super.init(nibName: nil, bundle: nil) configureOptions( @@ -34,7 +42,8 @@ final class OptionModalViewController: UIViewController { fatalError("init(coder:) has not been implemented") } - //MARK: - UI + // MARK: - UI + private var firstOptionButton: UIButton = UIButton() private var secondOptionButton: UIButton = UIButton() private var thirdOptionButton: UIButton = UIButton() @@ -104,16 +113,19 @@ private extension OptionModalViewController { icon: firstOption.icon, title: firstOption.title ) + firstOptionButton.isSelected = firstOption.isSelected self.secondOptionButton = self.generateOptionButton( icon: secondOption.icon, title: secondOption.title ) + secondOptionButton.isSelected = secondOption.isSelected self.thirdOptionButton = self.generateOptionButton( icon: thirdOption.icon, title: thirdOption.title ) + thirdOptionButton.isSelected = thirdOption.isSelected firstOptionButton.addAction(firstOption.acton, for: .touchUpInside) secondOptionButton.addAction(secondOption.acton, for: .touchUpInside) @@ -121,22 +133,8 @@ private extension OptionModalViewController { } func configureUI() { - let firstDividingLineView = generateDividingView() - let secondDividingLineView = generateDividingView() + let defaultHeight: CGFloat = type == .music ? 224 : 232 - let defaultHeigh: CGFloat = 224 - [ - firstOptionButton, - firstDividingLineView, - secondOptionButton, - secondDividingLineView, - thirdOptionButton - ].forEach { - optionStackView.addArrangedSubview($0) - } - - containerView.addSubview(optionStackView) - [dimmedView, containerView].forEach { view.addSubview($0) } @@ -147,30 +145,65 @@ private extension OptionModalViewController { containerView.snp.makeConstraints { $0.leading.bottom.trailing.equalToSuperview() - $0.height.equalTo(defaultHeigh) + $0.height.equalTo(defaultHeight) } + + switch type { + case .music: + let firstDividingLineView = generateDividingView() + let secondDividingLineView = generateDividingView() + + [ + firstOptionButton, + firstDividingLineView, + secondOptionButton, + secondDividingLineView, + thirdOptionButton + ].forEach { + optionStackView.addArrangedSubview($0) + } - optionStackView.snp.makeConstraints { - $0.leading.top.trailing.equalToSuperview().inset(16) - $0.bottom.equalTo(view.safeAreaLayoutGuide).inset(16) - } + containerView.addSubview(optionStackView) + optionStackView.snp.makeConstraints { + $0.leading.top.trailing.equalToSuperview().inset(16) + $0.bottom.equalTo(view.safeAreaLayoutGuide).inset(16) + } - firstDividingLineView.snp.makeConstraints { - $0.height.equalTo(2) - $0.leading.trailing.equalToSuperview() - } - - secondDividingLineView.snp.makeConstraints { - $0.height.equalTo(2) - $0.leading.trailing.equalToSuperview() - } + firstDividingLineView.snp.makeConstraints { + $0.height.equalTo(2) + $0.leading.trailing.equalToSuperview() + } + + secondDividingLineView.snp.makeConstraints { + $0.height.equalTo(2) + $0.leading.trailing.equalToSuperview() + } - firstOptionButton.snp.makeConstraints { - $0.height.equalTo(secondOptionButton.snp.height) - } - - secondOptionButton.snp.makeConstraints { - $0.height.equalTo(thirdOptionButton.snp.height) + firstOptionButton.snp.makeConstraints { + $0.height.equalTo(secondOptionButton.snp.height) + } + + secondOptionButton.snp.makeConstraints { + $0.height.equalTo(thirdOptionButton.snp.height) + } + + case .filterMusicList: + optionStackView.distribution = .fillEqually + optionStackView.alignment = .leading + + containerView.addSubview(optionStackView) + optionStackView.snp.makeConstraints { + $0.leading.top.trailing.equalToSuperview().inset(24) + $0.bottom.equalTo(view.safeAreaLayoutGuide).inset(16) + } + + [ + firstOptionButton, + secondOptionButton, + thirdOptionButton + ].forEach { + optionStackView.addArrangedSubview($0) + } } } } @@ -180,7 +213,13 @@ private extension OptionModalViewController { func generateOptionButton(icon: UIImage?, title: String) -> UIButton { //ui let button = UIButton() - button.setImage(icon, for: .normal) + switch type { + case .music: + button.setImage(icon, for: .normal) + case .filterMusicList: + button.setImage(icon, for: .selected) + } + button.setTitle(title, for: .normal) button.setTitleColor(.gray100, for: .normal) button.titleLabel?.font = .pretendard(size: 16, weightName: .medium) @@ -200,7 +239,7 @@ private extension OptionModalViewController { view.backgroundColor = .gray600 return view } - + @objc func dismiss(_ sender: UITapGestureRecognizer? = nil) { UIView.animate(withDuration: 0.1) { self.dimmedView.alpha = 0 diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/Contents.json new file mode 100644 index 00000000..9331cf93 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-selected.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/icon-selected.png b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/icon-selected.png new file mode 100644 index 00000000..b2cd7342 Binary files /dev/null and b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-selected.imageset/icon-selected.png differ