diff --git a/StreetDrop/StreetDrop.xcodeproj/project.pbxproj b/StreetDrop/StreetDrop.xcodeproj/project.pbxproj index cef54718..ec8d2bbf 100644 --- a/StreetDrop/StreetDrop.xcodeproj/project.pbxproj +++ b/StreetDrop/StreetDrop.xcodeproj/project.pbxproj @@ -23,8 +23,8 @@ 049F50222A122C8A001528CB /* DropMusicRequestDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049F50212A122C8A001528CB /* DropMusicRequestDTO+Mapping.swift */; }; 04FB1F262A0215BC0064B3C8 /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FB1F252A0215BC0064B3C8 /* MainViewModel.swift */; }; 04FB1F322A021C330064B3C8 /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FB1F312A021C330064B3C8 /* TestError.swift */; }; - 082F17062AB6DFEC00174D98 /* MusicDropUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17052AB6DFEC00174D98 /* MusicDropUseCase.swift */; }; - 082F17092AB6E41100174D98 /* DefaultMusicDropUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17082AB6E41100174D98 /* DefaultMusicDropUseCase.swift */; }; + 082F17062AB6DFEC00174D98 /* DropMusicUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17052AB6DFEC00174D98 /* DropMusicUseCase.swift */; }; + 082F17092AB6E41100174D98 /* DefaultDropMusicUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17082AB6E41100174D98 /* DefaultDropMusicUseCase.swift */; }; 082F171A2AB7454200174D98 /* EditCommentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17192AB7454200174D98 /* EditCommentUseCase.swift */; }; 082F171C2AB7455400174D98 /* DefaultEditCommentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F171B2AB7455400174D98 /* DefaultEditCommentUseCase.swift */; }; 082F17242ADD60BB00174D98 /* UINavigation+Gesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 082F17232ADD60BB00174D98 /* UINavigation+Gesture.swift */; }; @@ -43,8 +43,16 @@ 0856525D2B1F29FD00FD9BCB /* ModalOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0856525C2B1F29FD00FD9BCB /* ModalOption.swift */; }; 08810C2E2BD3FB00004FC6C1 /* LevelPolicyPopUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08810C2D2BD3FB00004FC6C1 /* LevelPolicyPopUpViewController.swift */; }; 08810C322BD3FC57004FC6C1 /* LevelPolicySubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08810C312BD3FC57004FC6C1 /* LevelPolicySubView.swift */; }; + 088F000B2CAACDB100F97992 /* String+ToDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088F000A2CAACDB100F97992 /* String+ToDate.swift */; }; + 088F000D2CAACE0D00F97992 /* Date+TimeAgoDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088F000C2CAACE0D00F97992 /* Date+TimeAgoDisplay.swift */; }; 08B97EA52B44303C00084F66 /* UniviersialLinkKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B97EA42B44303C00084F66 /* UniviersialLinkKey.swift */; }; 08BE57162BD4C887007EA949 /* UILabel+applyGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08BE57152BD4C887007EA949 /* UILabel+applyGradient.swift */; }; + 08F574512C4696AC00635B54 /* FetchingMyDropListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F574502C4696AC00635B54 /* FetchingMyDropListUseCase.swift */; }; + 08F574532C4696C600635B54 /* DefaultFetchingMyDropListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F574522C4696C600635B54 /* DefaultFetchingMyDropListUseCase.swift */; }; + 08F574562C4697E100635B54 /* FetchingMyLikeListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F574552C4697E100635B54 /* FetchingMyLikeListUseCase.swift */; }; + 08F574582C46985300635B54 /* DefaultFetchingMyLikeListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F574572C46985300635B54 /* DefaultFetchingMyLikeListUseCase.swift */; }; + 08F5745B2C4698B300635B54 /* FetchingMyLevelUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F5745A2C4698B300635B54 /* FetchingMyLevelUseCase.swift */; }; + 08F5745D2C46992500635B54 /* DefaultFetchingMyLevelUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F5745C2C46992500635B54 /* DefaultFetchingMyLevelUseCase.swift */; }; 1816ED3C2A680608005009FC /* MusicListSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1816ED3B2A680608005009FC /* MusicListSectionHeaderView.swift */; }; 1816ED3F2A68064E005009FC /* MyPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1816ED3E2A68064E005009FC /* MyPageViewModel.swift */; }; 1816ED412A685704005009FC /* NicknameEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1816ED402A685704005009FC /* NicknameEditViewModel.swift */; }; @@ -57,7 +65,7 @@ 1824F13A2A34A4B700A10320 /* MusicCountEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1824F1362A349F3700A10320 /* MusicCountEntity.swift */; }; 1824F13B2A34A4C900A10320 /* PoiEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18683FE02A349109005A94AC /* PoiEntity.swift */; }; 1867C8202A4DDB8C00F8EC48 /* MyPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1867C81F2A4DDB8C00F8EC48 /* MyPageViewController.swift */; }; - 1867C8242A4FFCDF00F8EC48 /* MusicTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1867C8232A4FFCDF00F8EC48 /* MusicTableViewCell.swift */; }; + 1867C8242A4FFCDF00F8EC48 /* MusicListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1867C8232A4FFCDF00F8EC48 /* MusicListCell.swift */; }; 18683FD92A2A251E005A94AC /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18683FD82A2A251E005A94AC /* ViewModel.swift */; }; 18683FDC2A348B15005A94AC /* DefaultMainRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18683FDB2A348B15005A94AC /* DefaultMainRepository.swift */; }; 18683FDF2A348B25005A94AC /* MainRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18683FDE2A348B25005A94AC /* MainRepository.swift */; }; @@ -66,7 +74,6 @@ 1876F03F2A66E4E30064B887 /* MyLikeListResponseDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F03E2A66E4E30064B887 /* MyLikeListResponseDTO+Mapping.swift */; }; 1876F0412A66E5440064B887 /* MyLevelResponseDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F0402A66E5440064B887 /* MyLevelResponseDTO+Mapping.swift */; }; 1876F0442A66E6E00064B887 /* MyPageRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F0432A66E6E00064B887 /* MyPageRepository.swift */; }; - 1876F0472A66EDA20064B887 /* MyPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F0462A66EDA20064B887 /* MyPageModel.swift */; }; 1876F04A2A66EDF10064B887 /* MyMusic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F0492A66EDF10064B887 /* MyMusic.swift */; }; 1876F04E2A66EE030064B887 /* MyLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F04D2A66EE030064B887 /* MyLevel.swift */; }; 1876F0502A66F7A30064B887 /* DefaultMyPageRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1876F04F2A66F7A30064B887 /* DefaultMyPageRepository.swift */; }; @@ -140,6 +147,12 @@ 6A26BF322B33D1E40007B6B7 /* FetchingSingleMusicUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A26BF312B33D1E40007B6B7 /* FetchingSingleMusicUseCase.swift */; }; 6A26BF342B33D2210007B6B7 /* DefaultFetchingSingleMusicUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A26BF332B33D2210007B6B7 /* DefaultFetchingSingleMusicUseCase.swift */; }; 6A3AFB582B8DB399003BD144 /* GADUnitID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A3AFB572B8DB399003BD144 /* GADUnitID.swift */; }; + 6A51EC3C2C3E52FE00DEF6F3 /* UIViewController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3B2C3E52FE00DEF6F3 /* UIViewController+Rx.swift */; }; + 6A51EC3E2C3E536000DEF6F3 /* Map+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A51EC3D2C3E536000DEF6F3 /* Map+Rx.swift */; }; + 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 */; }; @@ -162,8 +175,8 @@ C41972362ABDB3C000211222 /* DefaultFetchingPOIUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41972352ABDB3C000211222 /* DefaultFetchingPOIUseCase.swift */; }; C41972382ABDB49400211222 /* FetchingMusicCountUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41972372ABDB49400211222 /* FetchingMusicCountUseCase.swift */; }; C419723A2ABDB50B00211222 /* DefaultFetchingMusicCountUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41972392ABDB50B00211222 /* DefaultFetchingMusicCountUseCase.swift */; }; - C419723C2ABDB5AF00211222 /* FetchingMusicWithinArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = C419723B2ABDB5AF00211222 /* FetchingMusicWithinArea.swift */; }; - C419723E2ABDB5D600211222 /* DefaultFetchingMusicWithinArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinArea.swift */; }; + C419723C2ABDB5AF00211222 /* FetchingMusicWithinAreaUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C419723B2ABDB5AF00211222 /* FetchingMusicWithinAreaUseCase.swift */; }; + C419723E2ABDB5D600211222 /* DefaultFetchingMusicWithinAreaUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinAreaUseCase.swift */; }; C41972402ABDC3B000211222 /* LikingUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C419723F2ABDC3B000211222 /* LikingUseCase.swift */; }; C41972422ABDC3D600211222 /* DefaultLikingUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41972412ABDC3D600211222 /* DefaultLikingUseCase.swift */; }; C41972442ABDC43C00211222 /* ClaimingCommentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41972432ABDC43C00211222 /* ClaimingCommentUseCase.swift */; }; @@ -311,8 +324,8 @@ 049F50212A122C8A001528CB /* DropMusicRequestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DropMusicRequestDTO+Mapping.swift"; sourceTree = ""; }; 04FB1F252A0215BC0064B3C8 /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; }; 04FB1F312A021C330064B3C8 /* TestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestError.swift; sourceTree = ""; }; - 082F17052AB6DFEC00174D98 /* MusicDropUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicDropUseCase.swift; sourceTree = ""; }; - 082F17082AB6E41100174D98 /* DefaultMusicDropUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultMusicDropUseCase.swift; sourceTree = ""; }; + 082F17052AB6DFEC00174D98 /* DropMusicUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropMusicUseCase.swift; sourceTree = ""; }; + 082F17082AB6E41100174D98 /* DefaultDropMusicUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultDropMusicUseCase.swift; sourceTree = ""; }; 082F17192AB7454200174D98 /* EditCommentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCommentUseCase.swift; sourceTree = ""; }; 082F171B2AB7455400174D98 /* DefaultEditCommentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEditCommentUseCase.swift; sourceTree = ""; }; 082F17232ADD60BB00174D98 /* UINavigation+Gesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigation+Gesture.swift"; sourceTree = ""; }; @@ -322,8 +335,16 @@ 0856525C2B1F29FD00FD9BCB /* ModalOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalOption.swift; sourceTree = ""; }; 08810C2D2BD3FB00004FC6C1 /* LevelPolicyPopUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelPolicyPopUpViewController.swift; sourceTree = ""; }; 08810C312BD3FC57004FC6C1 /* LevelPolicySubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelPolicySubView.swift; sourceTree = ""; }; + 088F000A2CAACDB100F97992 /* String+ToDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ToDate.swift"; sourceTree = ""; }; + 088F000C2CAACE0D00F97992 /* Date+TimeAgoDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgoDisplay.swift"; sourceTree = ""; }; 08B97EA42B44303C00084F66 /* UniviersialLinkKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniviersialLinkKey.swift; sourceTree = ""; }; 08BE57152BD4C887007EA949 /* UILabel+applyGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+applyGradient.swift"; sourceTree = ""; }; + 08F574502C4696AC00635B54 /* FetchingMyDropListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMyDropListUseCase.swift; sourceTree = ""; }; + 08F574522C4696C600635B54 /* DefaultFetchingMyDropListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMyDropListUseCase.swift; sourceTree = ""; }; + 08F574552C4697E100635B54 /* FetchingMyLikeListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMyLikeListUseCase.swift; sourceTree = ""; }; + 08F574572C46985300635B54 /* DefaultFetchingMyLikeListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMyLikeListUseCase.swift; sourceTree = ""; }; + 08F5745A2C4698B300635B54 /* FetchingMyLevelUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMyLevelUseCase.swift; sourceTree = ""; }; + 08F5745C2C46992500635B54 /* DefaultFetchingMyLevelUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMyLevelUseCase.swift; sourceTree = ""; }; 1816ED3B2A680608005009FC /* MusicListSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicListSectionHeaderView.swift; sourceTree = ""; }; 1816ED3E2A68064E005009FC /* MyPageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewModel.swift; sourceTree = ""; }; 1816ED402A685704005009FC /* NicknameEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NicknameEditViewModel.swift; sourceTree = ""; }; @@ -332,7 +353,7 @@ 1816ED482A68591F005009FC /* DefaultNicknameEditRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultNicknameEditRepository.swift; sourceTree = ""; }; 1824F1362A349F3700A10320 /* MusicCountEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicCountEntity.swift; sourceTree = ""; }; 1867C81F2A4DDB8C00F8EC48 /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; - 1867C8232A4FFCDF00F8EC48 /* MusicTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicTableViewCell.swift; sourceTree = ""; }; + 1867C8232A4FFCDF00F8EC48 /* MusicListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicListCell.swift; sourceTree = ""; }; 18683FD82A2A251E005A94AC /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = ""; }; 18683FDB2A348B15005A94AC /* DefaultMainRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultMainRepository.swift; sourceTree = ""; }; 18683FDE2A348B25005A94AC /* MainRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRepository.swift; sourceTree = ""; }; @@ -341,7 +362,6 @@ 1876F03E2A66E4E30064B887 /* MyLikeListResponseDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MyLikeListResponseDTO+Mapping.swift"; sourceTree = ""; }; 1876F0402A66E5440064B887 /* MyLevelResponseDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MyLevelResponseDTO+Mapping.swift"; sourceTree = ""; }; 1876F0432A66E6E00064B887 /* MyPageRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageRepository.swift; sourceTree = ""; }; - 1876F0462A66EDA20064B887 /* MyPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageModel.swift; sourceTree = ""; }; 1876F0492A66EDF10064B887 /* MyMusic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyMusic.swift; sourceTree = ""; }; 1876F04D2A66EE030064B887 /* MyLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyLevel.swift; sourceTree = ""; }; 1876F04F2A66F7A30064B887 /* DefaultMyPageRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultMyPageRepository.swift; sourceTree = ""; }; @@ -410,6 +430,12 @@ 6A26BF312B33D1E40007B6B7 /* FetchingSingleMusicUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingSingleMusicUseCase.swift; sourceTree = ""; }; 6A26BF332B33D2210007B6B7 /* DefaultFetchingSingleMusicUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingSingleMusicUseCase.swift; sourceTree = ""; }; 6A3AFB572B8DB399003BD144 /* GADUnitID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GADUnitID.swift; sourceTree = ""; }; + 6A51EC3B2C3E52FE00DEF6F3 /* UIViewController+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Rx.swift"; sourceTree = ""; }; + 6A51EC3D2C3E536000DEF6F3 /* Map+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Map+Rx.swift"; sourceTree = ""; }; + 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 = ""; }; @@ -432,8 +458,8 @@ C41972352ABDB3C000211222 /* DefaultFetchingPOIUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingPOIUseCase.swift; sourceTree = ""; }; C41972372ABDB49400211222 /* FetchingMusicCountUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMusicCountUseCase.swift; sourceTree = ""; }; C41972392ABDB50B00211222 /* DefaultFetchingMusicCountUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMusicCountUseCase.swift; sourceTree = ""; }; - C419723B2ABDB5AF00211222 /* FetchingMusicWithinArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMusicWithinArea.swift; sourceTree = ""; }; - C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMusicWithinArea.swift; sourceTree = ""; }; + C419723B2ABDB5AF00211222 /* FetchingMusicWithinAreaUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchingMusicWithinAreaUseCase.swift; sourceTree = ""; }; + C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinAreaUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFetchingMusicWithinAreaUseCase.swift; sourceTree = ""; }; C419723F2ABDC3B000211222 /* LikingUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikingUseCase.swift; sourceTree = ""; }; C41972412ABDC3D600211222 /* DefaultLikingUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultLikingUseCase.swift; sourceTree = ""; }; C41972432ABDC43C00211222 /* ClaimingCommentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClaimingCommentUseCase.swift; sourceTree = ""; }; @@ -783,13 +809,13 @@ path = Error; sourceTree = ""; }; - 082F170A2AB6E42800174D98 /* MusicDrop */ = { + 082F170A2AB6E42800174D98 /* DropMusic */ = { isa = PBXGroup; children = ( - 082F17052AB6DFEC00174D98 /* MusicDropUseCase.swift */, - 082F17082AB6E41100174D98 /* DefaultMusicDropUseCase.swift */, + 082F17052AB6DFEC00174D98 /* DropMusicUseCase.swift */, + 082F17082AB6E41100174D98 /* DefaultDropMusicUseCase.swift */, ); - path = MusicDrop; + path = DropMusic; sourceTree = ""; }; 082F17182AB7451A00174D98 /* Domain */ = { @@ -804,50 +830,224 @@ 082F171D2AB7465A00174D98 /* UseCase */ = { isa = PBXGroup; children = ( - 082F17192AB7454200174D98 /* EditCommentUseCase.swift */, - 082F171B2AB7455400174D98 /* DefaultEditCommentUseCase.swift */, - C419722D2ABD9D6F00211222 /* MyInfoUseCase.swift */, - C419722F2ABDAB0200211222 /* DefaultMyInfoUseCase.swift */, - C4685B372B72605500F514C7 /* FetchingUserCircleRadiusUsecase.swift */, - C4685B392B72610600F514C7 /* DefaultFetchingUserCircleRadiusUsecase.swift */, - C41972332ABDB36600211222 /* FetchingPOIUseCase.swift */, - C41972352ABDB3C000211222 /* DefaultFetchingPOIUseCase.swift */, - C41972372ABDB49400211222 /* FetchingMusicCountUseCase.swift */, - C41972392ABDB50B00211222 /* DefaultFetchingMusicCountUseCase.swift */, - C419723B2ABDB5AF00211222 /* FetchingMusicWithinArea.swift */, - C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinArea.swift */, - C419723F2ABDC3B000211222 /* LikingUseCase.swift */, - C41972412ABDC3D600211222 /* DefaultLikingUseCase.swift */, - C41972432ABDC43C00211222 /* ClaimingCommentUseCase.swift */, - C41972452ABDC45000211222 /* DefaultClaimingCommentUseCase.swift */, - C41972472ABDC4C700211222 /* DeletingMusicUseCase.swift */, - C41972492ABDC94A00211222 /* DefaultDeletingMusicUseCase.swift */, - C419724B2ABDCA6100211222 /* BlockUserUseCase.swift */, - C419724D2ABDCABD00211222 /* DefaultBlockUserUseCase.swift */, - C41972542ABED3EC00211222 /* FetchingMyInfoUseCase.swift */, - C41972562ABED40100211222 /* DefaultFetchingMyInfoUseCase.swift */, - C434A4CD2A17970A00C63526 /* SearchMusicUsecase.swift */, - C4E4C6B72A5ADFDB00B1C84A /* SettingsUseCase.swift */, + 08F5746F2C469E7B00635B54 /* EditComment */, + 08F5746E2C469E7400635B54 /* MyInfo */, + 08F5746D2C469E5C00635B54 /* FetchingUserCircleRadius */, + 08F5746C2C469E5200635B54 /* FetchingPOI */, + 08F5746B2C469E4000635B54 /* FetchingMusicCount */, + 08F5746A2C469D9E00635B54 /* FetchingMusicWithinArea */, + 08F574692C469D9500635B54 /* Liking */, + 08F574682C469D8300635B54 /* ClaimingComment */, + 08F574672C469D7B00635B54 /* DeletingMusic */, + 08F574662C469D6F00635B54 /* BlockUser */, + 08F574652C469D6500635B54 /* FetchingMyInfo */, + 08F574712C469F2100635B54 /* SearchingMusic */, + 08F574722C469F2800635B54 /* Settings */, + 08F574642C469D4A00635B54 /* FetchingPopUpInfomation */, + 08F574632C469D2800635B54 /* PostingPopUpUserReading */, + 08F574622C469CFF00635B54 /* FetchingSingleMusic */, + 082F170A2AB6E42800174D98 /* DropMusic */, + 08F574702C469F1900635B54 /* FetchingNotice */, + 08F5745F2C46999800635B54 /* FetchingLevelPolicy */, + 08F5745E2C46993800635B54 /* FetchingMyLevel */, + 08F574592C46987B00635B54 /* FetchingMyLikeList */, + 08F574542C46979700635B54 /* FetchingMyDropList */, + ); + path = UseCase; + sourceTree = ""; + }; + 0856524E2AFA781E00FD9BCB /* SingleMusic */ = { + isa = PBXGroup; + children = ( + 0856524C2AFA77FD00FD9BCB /* SingleMusicResponseDTO.swift */, + ); + path = SingleMusic; + sourceTree = ""; + }; + 08F574542C46979700635B54 /* FetchingMyDropList */ = { + isa = PBXGroup; + children = ( + 08F574502C4696AC00635B54 /* FetchingMyDropListUseCase.swift */, + 08F574522C4696C600635B54 /* DefaultFetchingMyDropListUseCase.swift */, + ); + path = FetchingMyDropList; + sourceTree = ""; + }; + 08F574592C46987B00635B54 /* FetchingMyLikeList */ = { + isa = PBXGroup; + children = ( + 08F574552C4697E100635B54 /* FetchingMyLikeListUseCase.swift */, + 08F574572C46985300635B54 /* DefaultFetchingMyLikeListUseCase.swift */, + ); + path = FetchingMyLikeList; + sourceTree = ""; + }; + 08F5745E2C46993800635B54 /* FetchingMyLevel */ = { + isa = PBXGroup; + children = ( + 08F5745A2C4698B300635B54 /* FetchingMyLevelUseCase.swift */, + 08F5745C2C46992500635B54 /* DefaultFetchingMyLevelUseCase.swift */, + ); + path = FetchingMyLevel; + sourceTree = ""; + }; + 08F5745F2C46999800635B54 /* FetchingLevelPolicy */ = { + isa = PBXGroup; + children = ( + 6AAFD9AE2BCE567A001A6772 /* FetchingLevelPolicyUseCase.swift */, + 6AAFD9B02BCE56A6001A6772 /* DefaultFetchingLevelPolicyUseCase.swift */, + ); + path = FetchingLevelPolicy; + sourceTree = ""; + }; + 08F574622C469CFF00635B54 /* FetchingSingleMusic */ = { + isa = PBXGroup; + children = ( 6A26BF312B33D1E40007B6B7 /* FetchingSingleMusicUseCase.swift */, 6A26BF332B33D2210007B6B7 /* DefaultFetchingSingleMusicUseCase.swift */, - C44A54992BBC097E00354F8F /* FetchingPopUpInfomationUseCase.swift */, - C44A549B2BBC099E00354F8F /* DefaultFetchingPopUpInfomationUseCase.swift */, + ); + path = FetchingSingleMusic; + sourceTree = ""; + }; + 08F574632C469D2800635B54 /* PostingPopUpUserReading */ = { + isa = PBXGroup; + children = ( C449807B2BC3B07E0001E6C3 /* PostingPopUpUserReadingUseCase.swift */, C449807D2BC3B09F0001E6C3 /* DefaultPostingPopUpUserReadingUseCase.swift */, - 082F170A2AB6E42800174D98 /* MusicDrop */, - 6AAFD9AE2BCE567A001A6772 /* FetchingLevelPolicyUseCase.swift */, - 6AAFD9B02BCE56A6001A6772 /* DefaultFetchingLevelPolicyUseCase.swift */, + ); + path = PostingPopUpUserReading; + sourceTree = ""; + }; + 08F574642C469D4A00635B54 /* FetchingPopUpInfomation */ = { + isa = PBXGroup; + children = ( + C44A54992BBC097E00354F8F /* FetchingPopUpInfomationUseCase.swift */, + C44A549B2BBC099E00354F8F /* DefaultFetchingPopUpInfomationUseCase.swift */, + ); + path = FetchingPopUpInfomation; + sourceTree = ""; + }; + 08F574652C469D6500635B54 /* FetchingMyInfo */ = { + isa = PBXGroup; + children = ( + C41972542ABED3EC00211222 /* FetchingMyInfoUseCase.swift */, + C41972562ABED40100211222 /* DefaultFetchingMyInfoUseCase.swift */, + ); + path = FetchingMyInfo; + sourceTree = ""; + }; + 08F574662C469D6F00635B54 /* BlockUser */ = { + isa = PBXGroup; + children = ( + C419724B2ABDCA6100211222 /* BlockUserUseCase.swift */, + C419724D2ABDCABD00211222 /* DefaultBlockUserUseCase.swift */, + ); + path = BlockUser; + sourceTree = ""; + }; + 08F574672C469D7B00635B54 /* DeletingMusic */ = { + isa = PBXGroup; + children = ( + C41972472ABDC4C700211222 /* DeletingMusicUseCase.swift */, + C41972492ABDC94A00211222 /* DefaultDeletingMusicUseCase.swift */, + ); + path = DeletingMusic; + sourceTree = ""; + }; + 08F574682C469D8300635B54 /* ClaimingComment */ = { + isa = PBXGroup; + children = ( + C41972432ABDC43C00211222 /* ClaimingCommentUseCase.swift */, + C41972452ABDC45000211222 /* DefaultClaimingCommentUseCase.swift */, + ); + path = ClaimingComment; + sourceTree = ""; + }; + 08F574692C469D9500635B54 /* Liking */ = { + isa = PBXGroup; + children = ( + C419723F2ABDC3B000211222 /* LikingUseCase.swift */, + C41972412ABDC3D600211222 /* DefaultLikingUseCase.swift */, + ); + path = Liking; + sourceTree = ""; + }; + 08F5746A2C469D9E00635B54 /* FetchingMusicWithinArea */ = { + isa = PBXGroup; + children = ( + C419723B2ABDB5AF00211222 /* FetchingMusicWithinAreaUseCase.swift */, + C419723D2ABDB5D600211222 /* DefaultFetchingMusicWithinAreaUseCase.swift */, + ); + path = FetchingMusicWithinArea; + sourceTree = ""; + }; + 08F5746B2C469E4000635B54 /* FetchingMusicCount */ = { + isa = PBXGroup; + children = ( + C41972372ABDB49400211222 /* FetchingMusicCountUseCase.swift */, + C41972392ABDB50B00211222 /* DefaultFetchingMusicCountUseCase.swift */, + ); + path = FetchingMusicCount; + sourceTree = ""; + }; + 08F5746C2C469E5200635B54 /* FetchingPOI */ = { + isa = PBXGroup; + children = ( + C41972332ABDB36600211222 /* FetchingPOIUseCase.swift */, + C41972352ABDB3C000211222 /* DefaultFetchingPOIUseCase.swift */, + ); + path = FetchingPOI; + sourceTree = ""; + }; + 08F5746D2C469E5C00635B54 /* FetchingUserCircleRadius */ = { + isa = PBXGroup; + children = ( + C4685B372B72605500F514C7 /* FetchingUserCircleRadiusUsecase.swift */, + C4685B392B72610600F514C7 /* DefaultFetchingUserCircleRadiusUsecase.swift */, + ); + path = FetchingUserCircleRadius; + sourceTree = ""; + }; + 08F5746E2C469E7400635B54 /* MyInfo */ = { + isa = PBXGroup; + children = ( + C419722D2ABD9D6F00211222 /* MyInfoUseCase.swift */, + C419722F2ABDAB0200211222 /* DefaultMyInfoUseCase.swift */, + ); + path = MyInfo; + sourceTree = ""; + }; + 08F5746F2C469E7B00635B54 /* EditComment */ = { + isa = PBXGroup; + children = ( + 082F17192AB7454200174D98 /* EditCommentUseCase.swift */, + 082F171B2AB7455400174D98 /* DefaultEditCommentUseCase.swift */, + ); + path = EditComment; + sourceTree = ""; + }; + 08F574702C469F1900635B54 /* FetchingNotice */ = { + isa = PBXGroup; + children = ( F4C996A62C1EEC8600FF7B9A /* NoticeUseCase.swift */, ); - path = UseCase; + path = FetchingNotice; sourceTree = ""; }; - 0856524E2AFA781E00FD9BCB /* SingleMusic */ = { + 08F574712C469F2100635B54 /* SearchingMusic */ = { isa = PBXGroup; children = ( - 0856524C2AFA77FD00FD9BCB /* SingleMusicResponseDTO.swift */, + C434A4CD2A17970A00C63526 /* SearchMusicUsecase.swift */, ); - path = SingleMusic; + path = SearchingMusic; + sourceTree = ""; + }; + 08F574722C469F2800635B54 /* Settings */ = { + isa = PBXGroup; + children = ( + C4E4C6B72A5ADFDB00B1C84A /* SettingsUseCase.swift */, + ); + path = Settings; sourceTree = ""; }; 1816ED3D2A680640005009FC /* ViewModel */ = { @@ -902,12 +1102,12 @@ isa = PBXGroup; children = ( 1867C81F2A4DDB8C00F8EC48 /* MyPageViewController.swift */, - 1867C8232A4FFCDF00F8EC48 /* MusicTableViewCell.swift */, 18EF9FC82A5C51FB00266D27 /* NicknameEditViewController.swift */, - 1816ED3B2A680608005009FC /* MusicListSectionHeaderView.swift */, - 0856524F2AFBB73100FD9BCB /* MyPageType.swift */, + 6A51EC6A2C49F29C00DEF6F3 /* TabBar */, + 6A51EC6B2C49F2BA00DEF6F3 /* MusicList */, 6A7D73D82BB11A0E009340E3 /* LevelUpGuideView.swift */, 6A7D73DC2BB14015009340E3 /* GradientProgressBar.swift */, + 6A51EC6C2C49F2FA00DEF6F3 /* FilterType.swift */, ); path = View; sourceTree = ""; @@ -966,7 +1166,6 @@ isa = PBXGroup; children = ( 1876F0482A66EDE60064B887 /* Entites */, - 1876F0462A66EDA20064B887 /* MyPageModel.swift */, 1816ED422A685865005009FC /* NicknameEditModel.swift */, ); path = Model; @@ -1220,6 +1419,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 = ( @@ -1475,6 +1694,10 @@ 6A1386AA2B4F8A5000E49BB5 /* String+Base64.swift */, C49EDACD2BBD7EFE0025DB55 /* GradientLabel.swift */, F4AA84DE2C1F3B0200CADB1A /* Array+Extension.swift */, + 6A51EC3B2C3E52FE00DEF6F3 /* UIViewController+Rx.swift */, + 6A51EC3D2C3E536000DEF6F3 /* Map+Rx.swift */, + 088F000A2CAACDB100F97992 /* String+ToDate.swift */, + 088F000C2CAACE0D00F97992 /* Date+TimeAgoDisplay.swift */, ); path = Extensions; sourceTree = ""; @@ -1816,6 +2039,7 @@ F48DF73A2C1DD8F500F6DEA1 /* SettingPushNotificationCell.swift in Sources */, C4A445902A5EF225008279C1 /* FCMTokenRequestDTO.swift in Sources */, C46410F42A629820009DD88F /* MusicAppButton.swift in Sources */, + 08F574532C4696C600635B54 /* DefaultFetchingMyDropListUseCase.swift in Sources */, C41972512ABED0FE00211222 /* MyInfoRepository.swift in Sources */, C41972382ABDB49400211222 /* FetchingMusicCountUseCase.swift in Sources */, 41396D872A4EFA2900B69341 /* MyInfoResponseDTO.swift in Sources */, @@ -1828,12 +2052,15 @@ 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 */, C41972532ABED14200211222 /* DefaultMyInfoRepository.swift in Sources */, 6A7D73D92BB11A0E009340E3 /* LevelUpGuideView.swift in Sources */, 41396DA12A51B0DF00B69341 /* EditCommentViewController.swift in Sources */, C44A549A2BBC097E00354F8F /* FetchingPopUpInfomationUseCase.swift in Sources */, + 08F574562C4697E100635B54 /* FetchingMyLikeListUseCase.swift in Sources */, 41008EBA2A49B56F00FD4ABE /* ClaimModalViewController.swift in Sources */, C45BF3AC2A1EF64300CEDE74 /* RecentQueryButton.swift in Sources */, B4B9EE842ADBDFFB000A6507 /* RecommendMusicSearchCollectionView.swift in Sources */, @@ -1841,6 +2068,7 @@ 41A3DDF12A593ED4004CFA2F /* AlertViewController.swift in Sources */, C47F02222A38633500F48884 /* SettingsViewController.swift in Sources */, C44A54982BBC08D200354F8F /* DefaultPopUpRepository.swift in Sources */, + 088F000D2CAACE0D00F97992 /* Date+TimeAgoDisplay.swift in Sources */, C434A4DC2A19CA6F00C63526 /* SearchingMusicTableViewCell.swift in Sources */, 18D671F62A35C5D4003B1A71 /* UIImage+Resizing.swift in Sources */, C4E4C6B42A5ADC4B00B1C84A /* DefaultSettingsRepository.swift in Sources */, @@ -1854,6 +2082,7 @@ 414345232A35B9A3003FEE2A /* LikeMusicRepository.swift in Sources */, 040685042A01539800377094 /* MainViewController.swift in Sources */, C4685B362B725FF500F514C7 /* UserCircleRadiusResponseDTO.swift in Sources */, + 08F574582C46985300635B54 /* DefaultFetchingMyLikeListUseCase.swift in Sources */, 040685002A01539800377094 /* AppDelegate.swift in Sources */, C47583A12A5F11BD00CA7335 /* Bundle+APIKeys.swift in Sources */, C472B1882AC5523300482B2D /* DroppingInfo.swift in Sources */, @@ -1869,6 +2098,7 @@ F4C996A12C1E15CD00FF7B9A /* NoticeListViewController.swift in Sources */, 1867C8202A4DDB8C00F8EC48 /* MyPageViewController.swift in Sources */, 1816ED432A685865005009FC /* NicknameEditModel.swift in Sources */, + 6A51EC402C411FB000DEF6F3 /* MusicListTableView.swift in Sources */, C40008EA2A32012B00EA7FA9 /* Music.swift in Sources */, 413ABEEC2A39D1E900EA1010 /* UIcolor+.swift in Sources */, 41A9BEBB2A4DCBDA00F3605C /* DefaultClaimCommentRepository.swift in Sources */, @@ -1880,11 +2110,12 @@ C44A549C2BBC099E00354F8F /* DefaultFetchingPopUpInfomationUseCase.swift in Sources */, 082F17242ADD60BB00174D98 /* UINavigation+Gesture.swift in Sources */, 415113272A165DC50051F809 /* MusicDropViewController.swift in Sources */, - 1867C8242A4FFCDF00F8EC48 /* MusicTableViewCell.swift in Sources */, + 1867C8242A4FFCDF00F8EC48 /* MusicListCell.swift in Sources */, C45BF3A12A1D133000CEDE74 /* RecentMusicQueryDTO.swift in Sources */, 040685002A01539800377094 /* AppDelegate.swift in Sources */, 18CB7BED2A359F53002B31FB /* MusicWithinAreaEntity.swift in Sources */, C41972482ABDC4C700211222 /* DeletingMusicUseCase.swift in Sources */, + 08F5745B2C4698B300635B54 /* FetchingMyLevelUseCase.swift in Sources */, C4E4C6B82A5ADFDB00B1C84A /* SettingsUseCase.swift in Sources */, 41396D912A4EFBF700B69341 /* DefaultEditCommentRepository.swift in Sources */, C419722E2ABD9D6F00211222 /* MyInfoUseCase.swift in Sources */, @@ -1895,6 +2126,7 @@ C434A4D32A17983A00C63526 /* SearchingMusicRepository.swift in Sources */, C45BF39E2A1D113200CEDE74 /* UserDefaultsRecentMusicSearches.swift in Sources */, 6A1386AB2B4F8A5000E49BB5 /* String+Base64.swift in Sources */, + 6A51EC692C48F53400DEF6F3 /* MusicListFilterView.swift in Sources */, 41396D8B2A4EFB2500B69341 /* EditCommentRepository.swift in Sources */, F4AA84E12C1F732800CADB1A /* DateManager.swift in Sources */, 1816ED3F2A68064E005009FC /* MyPageViewModel.swift in Sources */, @@ -1920,13 +2152,14 @@ 4143452E2A373550003FEE2A /* AddressManager.swift in Sources */, 08BE57162BD4C887007EA949 /* UILabel+applyGradient.swift in Sources */, 18EF9FC92A5C51FB00266D27 /* NicknameEditViewController.swift in Sources */, + 6A51EC672C48F22600DEF6F3 /* TapListView.swift in Sources */, C44A54932BBC07AA00354F8F /* PopUpInfomation.swift in Sources */, B4B9EE862ADEB2AC000A6507 /* RecommendKeywordItemCell.swift in Sources */, 18683FDF2A348B25005A94AC /* MainRepository.swift in Sources */, 085652522B00B68100FD9BCB /* BubbleCommentView.swift in Sources */, 41A3DDF62A5AD1C7004CFA2F /* BlockUserRepository.swift in Sources */, 085652502AFBB73100FD9BCB /* MyPageType.swift in Sources */, - C419723C2ABDB5AF00211222 /* FetchingMusicWithinArea.swift in Sources */, + C419723C2ABDB5AF00211222 /* FetchingMusicWithinAreaUseCase.swift in Sources */, C434A4CE2A17970A00C63526 /* SearchMusicUsecase.swift in Sources */, 414345252A35B9C3003FEE2A /* DefaultLikeMusicRepository.swift in Sources */, 1816ED412A685704005009FC /* NicknameEditViewModel.swift in Sources */, @@ -1943,7 +2176,6 @@ F4C996AD2C1EEF2500FF7B9A /* NoticeRepository.swift in Sources */, F4AA84DB2C1F106300CADB1A /* NoticeDetailViewController.swift in Sources */, C47F02282A3864A500F48884 /* SettingElementCell.swift in Sources */, - 1876F0472A66EDA20064B887 /* MyPageModel.swift in Sources */, 18683FDC2A348B15005A94AC /* DefaultMainRepository.swift in Sources */, 1876F03F2A66E4E30064B887 /* MyLikeListResponseDTO+Mapping.swift in Sources */, 6A7D73DD2BB14015009340E3 /* GradientProgressBar.swift in Sources */, @@ -1954,12 +2186,13 @@ 41396DA42A51B61000B69341 /* EditCommentViewModel.swift in Sources */, 049F50222A122C8A001528CB /* DropMusicRequestDTO+Mapping.swift in Sources */, C49EDACC2BBD75480025DB55 /* CongratulationsLevelUpPopUpViewController.swift in Sources */, + 6A51EC3C2C3E52FE00DEF6F3 /* UIViewController+Rx.swift in Sources */, F4C996AF2C1EF6C100FF7B9A /* Notice.swift in Sources */, 41A9BEB92A4DCA4A00F3605C /* ClaimCommentRepository.swift in Sources */, C45BF3A32A1D179C00CEDE74 /* RecentMusicQueriesStorage.swift in Sources */, 041038972A126E7B00BC5532 /* MusicCountByDongResponseDTO+Mapping.swift in Sources */, 41396D992A4F04D800B69341 /* UserDefaultsMyInfoStorage.swift in Sources */, - C419723E2ABDB5D600211222 /* DefaultFetchingMusicWithinArea.swift in Sources */, + C419723E2ABDB5D600211222 /* DefaultFetchingMusicWithinAreaUseCase.swift in Sources */, F4C996AA2C1EEF0B00FF7B9A /* DefaultNoticeRepository.swift in Sources */, 41396D972A4F04CB00B69341 /* MyInfoStorage.swift in Sources */, 1824F1372A349F3700A10320 /* MusicCountEntity.swift in Sources */, @@ -1970,11 +2203,12 @@ C419724E2ABDCABD00211222 /* DefaultBlockUserUseCase.swift in Sources */, 1876F0412A66E5440064B887 /* MyLevelResponseDTO+Mapping.swift in Sources */, C4685B3D2B7261A000F514C7 /* SplashViewModel.swift in Sources */, + 088F000B2CAACDB100F97992 /* String+ToDate.swift in Sources */, F4AA84DF2C1F3B0200CADB1A /* Array+Extension.swift in Sources */, - 082F17062AB6DFEC00174D98 /* MusicDropUseCase.swift in Sources */, + 082F17062AB6DFEC00174D98 /* DropMusicUseCase.swift in Sources */, 18683FD92A2A251E005A94AC /* ViewModel.swift in Sources */, C41972442ABDC43C00211222 /* ClaimingCommentUseCase.swift in Sources */, - 082F17092AB6E41100174D98 /* DefaultMusicDropUseCase.swift in Sources */, + 082F17092AB6E41100174D98 /* DefaultDropMusicUseCase.swift in Sources */, 08810C2E2BD3FB00004FC6C1 /* LevelPolicyPopUpViewController.swift in Sources */, C449807A2BC3AF9F0001E6C3 /* PopUpUserReadingRequestDTO.swift in Sources */, 412D668A2A1E14B600BA4A1B /* CommunityViewController.swift in Sources */, @@ -1985,6 +2219,7 @@ 41E008CE2A1442A000F5D99C /* PoiResponseDTO+Mapping.swift in Sources */, 41008EB82A48891000FD4ABE /* UITextView+setLineSpacing.swift in Sources */, C434A4CC2A1796F300C63526 /* SearchingMusicViewModel.swift in Sources */, + 08F574512C4696AC00635B54 /* FetchingMyDropListUseCase.swift in Sources */, 0856525D2B1F29FD00FD9BCB /* ModalOption.swift in Sources */, C4E4C6B22A5ADC2C00B1C84A /* SettingsRepository.swift in Sources */, C4E0943B2A4DF002000B4513 /* VillageNameResponseDTO.swift in Sources */, @@ -2002,6 +2237,7 @@ 188D2C7B2A1E448C0088F49C /* DroppedMusicWithinAreaCollectionViewCell.swift in Sources */, 41396D9B2A4F1C5600B69341 /* OptionModalViewController.swift in Sources */, C47C1D1F2A643C07007317EA /* SplashViewController.swift in Sources */, + 6A51EC3E2C3E536000DEF6F3 /* Map+Rx.swift in Sources */, C449807C2BC3B07E0001E6C3 /* PostingPopUpUserReadingUseCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/StreetDrop/StreetDrop/Data/DataMapping/MyDropList/MyDropListResponseDTO+Mapping.swift b/StreetDrop/StreetDrop/Data/DataMapping/MyDropList/MyDropListResponseDTO+Mapping.swift index fcfec8e1..cadac09a 100644 --- a/StreetDrop/StreetDrop/Data/DataMapping/MyDropList/MyDropListResponseDTO+Mapping.swift +++ b/StreetDrop/StreetDrop/Data/DataMapping/MyDropList/MyDropListResponseDTO+Mapping.swift @@ -23,10 +23,11 @@ struct MyDropListResponseDTO: Decodable { let music: Music let content, createdAt: String let itemLikeCount: Int + let isLiked: Bool enum CodingKeys: String, CodingKey { case itemID = "itemId" - case location, user, music, content, createdAt, itemLikeCount + case location, user, music, content, createdAt, itemLikeCount, isLiked } } @@ -76,7 +77,8 @@ extension MyDropListResponseDTO { comment: value.content, createdAt: value.createdAt, location: value.location.address, - likeCount: value.itemLikeCount + likeCount: value.itemLikeCount, + isLiked: value.isLiked ) } ) diff --git a/StreetDrop/StreetDrop/Data/DataMapping/MyLikeList/MyLikeListResponseDTO+Mapping.swift b/StreetDrop/StreetDrop/Data/DataMapping/MyLikeList/MyLikeListResponseDTO+Mapping.swift index 8810aa12..6842eef7 100644 --- a/StreetDrop/StreetDrop/Data/DataMapping/MyLikeList/MyLikeListResponseDTO+Mapping.swift +++ b/StreetDrop/StreetDrop/Data/DataMapping/MyLikeList/MyLikeListResponseDTO+Mapping.swift @@ -76,7 +76,8 @@ extension MyLikeListResponseDTO { comment: value.content, createdAt: value.createdAt, location: value.location.address, - likeCount: value.itemLikeCount + likeCount: value.itemLikeCount, + isLiked: true ) } ) diff --git a/StreetDrop/StreetDrop/Data/Repositories/MyPage/DefaultMyPageRepository.swift b/StreetDrop/StreetDrop/Data/Repositories/MyPage/DefaultMyPageRepository.swift index 5586176f..40bf5e2b 100644 --- a/StreetDrop/StreetDrop/Data/Repositories/MyPage/DefaultMyPageRepository.swift +++ b/StreetDrop/StreetDrop/Data/Repositories/MyPage/DefaultMyPageRepository.swift @@ -18,9 +18,9 @@ final class DefaultMyPageRepository { } extension DefaultMyPageRepository: MyPageRepository { - func fetchMyDropList() -> Single { + func fetchMyDropList(filterType: FilterType) -> Single { return networkManager.request( - target: .init(NetworkService.myDropList), + target: .init(NetworkService.myDropList(filterType: filterType.param)), responseType: MyDropListResponseDTO.self ) .map { dto in @@ -28,9 +28,9 @@ extension DefaultMyPageRepository: MyPageRepository { } } - func fetchMyLikeList() -> Single { + func fetchMyLikeList(filterType: FilterType) -> Single { return networkManager.request( - target: .init(NetworkService.myLikeList), + target: .init(NetworkService.myLikeList(filterType: filterType.param)), responseType: MyLikeListResponseDTO.self ) .map { dto in diff --git a/StreetDrop/StreetDrop/Data/Repositories/Protocol/MyPage/MyPageRepository.swift b/StreetDrop/StreetDrop/Data/Repositories/Protocol/MyPage/MyPageRepository.swift index d40218cb..7d920052 100644 --- a/StreetDrop/StreetDrop/Data/Repositories/Protocol/MyPage/MyPageRepository.swift +++ b/StreetDrop/StreetDrop/Data/Repositories/Protocol/MyPage/MyPageRepository.swift @@ -10,8 +10,8 @@ import Foundation import RxSwift protocol MyPageRepository { - func fetchMyDropList() -> Single - func fetchMyLikeList() -> Single + func fetchMyDropList(filterType: FilterType) -> Single + func fetchMyLikeList(filterType: FilterType) -> Single func fetchMyLevel() -> Single func fetchMyLevelProgress() -> Single func fetchLevelPolicy() -> Single<[LevelPolicy]> 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/Domain/UseCase/BlockUserUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/BlockUser/BlockUserUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/BlockUserUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/BlockUser/BlockUserUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultBlockUserUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/BlockUser/DefaultBlockUserUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultBlockUserUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/BlockUser/DefaultBlockUserUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/ClaimingCommentUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/ClaimingComment/ClaimingCommentUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/ClaimingCommentUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/ClaimingComment/ClaimingCommentUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultClaimingCommentUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/ClaimingComment/DefaultClaimingCommentUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultClaimingCommentUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/ClaimingComment/DefaultClaimingCommentUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultDeletingMusicUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/DeletingMusic/DefaultDeletingMusicUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultDeletingMusicUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/DeletingMusic/DefaultDeletingMusicUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DeletingMusicUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/DeletingMusic/DeletingMusicUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DeletingMusicUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/DeletingMusic/DeletingMusicUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/DefaultMusicDropUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DefaultDropMusicUseCase.swift similarity index 84% rename from StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/DefaultMusicDropUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DefaultDropMusicUseCase.swift index 131e2fd2..e00355f2 100644 --- a/StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/DefaultMusicDropUseCase.swift +++ b/StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DefaultDropMusicUseCase.swift @@ -1,5 +1,5 @@ // -// DefaultMusicDropUseCase.swift +// DefaultDropMusicUseCase.swift // StreetDrop // // Created by thoonk on 2023/09/17. @@ -9,7 +9,7 @@ import Foundation import RxSwift -final class DefaultMusicDropUseCase: MusicDropUseCase { +final class DefaultDropMusicUseCase: DropMusicUseCase { private let dropMusicRepository: DropMusicRepository init(dropMusicRepository: DropMusicRepository = DefaultDropMusicRepository()) { diff --git a/StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/MusicDropUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DropMusicUseCase.swift similarity index 75% rename from StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/MusicDropUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DropMusicUseCase.swift index 49e4f11c..bbcfea53 100644 --- a/StreetDrop/StreetDrop/Domain/UseCase/MusicDrop/MusicDropUseCase.swift +++ b/StreetDrop/StreetDrop/Domain/UseCase/DropMusic/DropMusicUseCase.swift @@ -1,5 +1,5 @@ // -// MusicDropUseCase.swift +// DropMusicUseCase.swift // StreetDrop // // Created by thoonk on 2023/09/17. @@ -9,6 +9,6 @@ import Foundation import RxSwift -protocol MusicDropUseCase { +protocol DropMusicUseCase { func drop(droppingInfo: DroppingInfo, content: String) -> Single } diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultEditCommentUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/EditComment/DefaultEditCommentUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultEditCommentUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/EditComment/DefaultEditCommentUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/EditCommentUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/EditComment/EditCommentUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/EditCommentUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/EditComment/EditCommentUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingLevelPolicyUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicy/DefaultFetchingLevelPolicyUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingLevelPolicyUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicy/DefaultFetchingLevelPolicyUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicyUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicy/FetchingLevelPolicyUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicyUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingLevelPolicy/FetchingLevelPolicyUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMusicCountUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCount/DefaultFetchingMusicCountUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMusicCountUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCount/DefaultFetchingMusicCountUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCountUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCount/FetchingMusicCountUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCountUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicCount/FetchingMusicCountUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMusicWithinArea.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/DefaultFetchingMusicWithinAreaUseCase.swift similarity index 80% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMusicWithinArea.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/DefaultFetchingMusicWithinAreaUseCase.swift index a7497d94..a1597650 100644 --- a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMusicWithinArea.swift +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/DefaultFetchingMusicWithinAreaUseCase.swift @@ -1,5 +1,5 @@ // -// DefaultFetchingMusicWithinArea.swift +// DefaultFetchingMusicWithinAreaUseCase.swift // StreetDrop // // Created by 차요셉 on 2023/09/22. @@ -9,7 +9,7 @@ import Foundation import RxSwift -final class DefaultFetchingMusicWithinArea: FetchingMusicWithinArea { +final class DefaultFetchingMusicWithinAreaUseCase: FetchingMusicWithinAreaUseCase { private let mainRepository: MainRepository init(mainRepository: MainRepository = DefaultMainRepository( diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/FetchingMusicWithinAreaUseCase.swift similarity index 83% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/FetchingMusicWithinAreaUseCase.swift index fd5086a3..a9eb59ee 100644 --- a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea.swift +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMusicWithinArea/FetchingMusicWithinAreaUseCase.swift @@ -9,6 +9,6 @@ import Foundation import RxSwift -protocol FetchingMusicWithinArea { +protocol FetchingMusicWithinAreaUseCase { func execute(lat: Double, lon: Double, distance: Double) -> Single } diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/DefaultFetchingMyDropListUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/DefaultFetchingMyDropListUseCase.swift new file mode 100644 index 00000000..e24c43d5 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/DefaultFetchingMyDropListUseCase.swift @@ -0,0 +1,24 @@ +// +// DefaultFetchingMyDropListUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +final class DefaultFetchingMyDropListUseCase { + private let repository: MyPageRepository + + init(repository: MyPageRepository = DefaultMyPageRepository()) { + self.repository = repository + } +} + +extension DefaultFetchingMyDropListUseCase: FetchingMyDropListUseCase { + func fetchMyDropList(filterType: FilterType) -> Single { + return repository.fetchMyDropList(filterType: filterType) + } +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/FetchingMyDropListUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/FetchingMyDropListUseCase.swift new file mode 100644 index 00000000..91c8fb91 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyDropList/FetchingMyDropListUseCase.swift @@ -0,0 +1,14 @@ +// +// FetchingMyDropListUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +protocol FetchingMyDropListUseCase { + func fetchMyDropList(filterType: FilterType) -> Single +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMyInfoUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfo/DefaultFetchingMyInfoUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingMyInfoUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfo/DefaultFetchingMyInfoUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfoUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfo/FetchingMyInfoUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfoUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingMyInfo/FetchingMyInfoUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/DefaultFetchingMyLevelUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/DefaultFetchingMyLevelUseCase.swift new file mode 100644 index 00000000..fd466d07 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/DefaultFetchingMyLevelUseCase.swift @@ -0,0 +1,28 @@ +// +// DefaultFetchingMyLevelUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +final class DefaultFetchingMyLevelUseCase { + private let repository: MyPageRepository + + init(repository: MyPageRepository = DefaultMyPageRepository()) { + self.repository = repository + } +} + +extension DefaultFetchingMyLevelUseCase: FetchingMyLevelUseCase { + func fetchMyLevel() -> Single { + return repository.fetchMyLevel() + } + + func fetchMyLevelProgress() -> Single { + return repository.fetchMyLevelProgress() + } +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/FetchingMyLevelUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/FetchingMyLevelUseCase.swift new file mode 100644 index 00000000..1fe44ff5 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLevel/FetchingMyLevelUseCase.swift @@ -0,0 +1,15 @@ +// +// FetchingMyLevelUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +protocol FetchingMyLevelUseCase { + func fetchMyLevel() -> Single + func fetchMyLevelProgress() -> Single +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/DefaultFetchingMyLikeListUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/DefaultFetchingMyLikeListUseCase.swift new file mode 100644 index 00000000..ec13cf62 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/DefaultFetchingMyLikeListUseCase.swift @@ -0,0 +1,24 @@ +// +// DefaultFetchingMyLikeListUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +final class DefaultFetchingMyLikeListUseCase { + private let repository: MyPageRepository + + init(repository: MyPageRepository = DefaultMyPageRepository()) { + self.repository = repository + } +} + +extension DefaultFetchingMyLikeListUseCase: FetchingMyLikeListUseCase { + func fetchMyLikeList(filterType: FilterType) -> Single { + return repository.fetchMyLikeList(filterType: filterType) + } +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/FetchingMyLikeListUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/FetchingMyLikeListUseCase.swift new file mode 100644 index 00000000..2eb76b02 --- /dev/null +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingMyLikeList/FetchingMyLikeListUseCase.swift @@ -0,0 +1,14 @@ +// +// FetchingMyLikeListUseCase.swift +// StreetDrop +// +// Created by thoonk on 7/16/24. +// + +import Foundation + +import RxSwift + +protocol FetchingMyLikeListUseCase { + func fetchMyLikeList(filterType: FilterType) -> Single +} diff --git a/StreetDrop/StreetDrop/Domain/UseCase/NoticeUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingNotice/NoticeUseCase.swift similarity index 87% rename from StreetDrop/StreetDrop/Domain/UseCase/NoticeUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingNotice/NoticeUseCase.swift index 4b6a900c..11bda8d3 100644 --- a/StreetDrop/StreetDrop/Domain/UseCase/NoticeUseCase.swift +++ b/StreetDrop/StreetDrop/Domain/UseCase/FetchingNotice/NoticeUseCase.swift @@ -9,12 +9,12 @@ import Foundation import RxSwift -protocol NoticeUseCase { +protocol FetchingNoticeUseCase { func fetchNoticeList() -> Single<[NoticeEntity]> func fetchNoticeDetail(id: Int) -> Single } -final class DefaultNoticeUseCase: NoticeUseCase { +final class DefaultFetchingNoticeUseCase: FetchingNoticeUseCase { private let noticeRepository: NoticeRepository init(noticeRepository: NoticeRepository = DefaultNoticeRepository()) { diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingPOIUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingPOI/DefaultFetchingPOIUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingPOIUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingPOI/DefaultFetchingPOIUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingPOIUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingPOI/FetchingPOIUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingPOIUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingPOI/FetchingPOIUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingPopUpInfomationUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomation/DefaultFetchingPopUpInfomationUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingPopUpInfomationUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomation/DefaultFetchingPopUpInfomationUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomationUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomation/FetchingPopUpInfomationUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomationUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingPopUpInfomation/FetchingPopUpInfomationUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingSingleMusicUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusic/DefaultFetchingSingleMusicUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingSingleMusicUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusic/DefaultFetchingSingleMusicUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusicUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusic/FetchingSingleMusicUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusicUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingSingleMusic/FetchingSingleMusicUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingUserCircleRadiusUsecase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadius/DefaultFetchingUserCircleRadiusUsecase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultFetchingUserCircleRadiusUsecase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadius/DefaultFetchingUserCircleRadiusUsecase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadiusUsecase.swift b/StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadius/FetchingUserCircleRadiusUsecase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadiusUsecase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/FetchingUserCircleRadius/FetchingUserCircleRadiusUsecase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultLikingUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/Liking/DefaultLikingUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultLikingUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/Liking/DefaultLikingUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/LikingUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/Liking/LikingUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/LikingUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/Liking/LikingUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultMyInfoUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/MyInfo/DefaultMyInfoUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultMyInfoUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/MyInfo/DefaultMyInfoUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/MyInfoUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/MyInfo/MyInfoUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/MyInfoUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/MyInfo/MyInfoUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/DefaultPostingPopUpUserReadingUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReading/DefaultPostingPopUpUserReadingUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/DefaultPostingPopUpUserReadingUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReading/DefaultPostingPopUpUserReadingUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReadingUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReading/PostingPopUpUserReadingUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReadingUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/PostingPopUpUserReading/PostingPopUpUserReadingUseCase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/SearchMusicUsecase.swift b/StreetDrop/StreetDrop/Domain/UseCase/SearchingMusic/SearchMusicUsecase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/SearchMusicUsecase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/SearchingMusic/SearchMusicUsecase.swift diff --git a/StreetDrop/StreetDrop/Domain/UseCase/SettingsUseCase.swift b/StreetDrop/StreetDrop/Domain/UseCase/Settings/SettingsUseCase.swift similarity index 100% rename from StreetDrop/StreetDrop/Domain/UseCase/SettingsUseCase.swift rename to StreetDrop/StreetDrop/Domain/UseCase/Settings/SettingsUseCase.swift diff --git a/StreetDrop/StreetDrop/Network/NetworkService.swift b/StreetDrop/StreetDrop/Network/NetworkService.swift index 9759db5b..8fea4d4e 100644 --- a/StreetDrop/StreetDrop/Network/NetworkService.swift +++ b/StreetDrop/StreetDrop/Network/NetworkService.swift @@ -28,8 +28,8 @@ enum NetworkService { case blockUser(blockUserID: Int) case postFCMToken(token: FCMTokenRequestDTO) case patchUsersMusicApp(musicAppQuery: String) - case myDropList - case myLikeList + case myDropList(filterType: String) + case myLikeList(filterType: String) case myLevel case myLevelProgress case levelPolicy @@ -96,7 +96,7 @@ extension NetworkService: TargetType { case .patchUsersMusicApp: return "/users/music-app" case .myDropList: - return "/users/me/items/drop" + return "/v2/users/me/items/drop" case .myLikeList: return "/users/me/items/like" case .myLevel: @@ -161,9 +161,11 @@ extension NetworkService: TargetType { var task: Moya.Task { switch self { - case .getMyInfo, .myDropList, .myLikeList, .myLevel, .myLevelProgress, .levelPolicy, .recommendMusic, .userCircleRadius, .getPopUpInfomation, + case .getMyInfo, .myLevel, .myLevelProgress, .levelPolicy, .recommendMusic, .userCircleRadius, .getPopUpInfomation, .getNoticeList, .getNoticeDetail: return .requestPlain + case .myDropList(let filterType), .myLikeList(let filterType): + return .requestParameters(parameters: ["orderType": filterType], encoding: URLEncoding.default) case .searchMusic(let keyword): return .requestParameters( parameters: ["keyword": keyword], 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/MainScene/ViewModel/MainViewModel.swift b/StreetDrop/StreetDrop/Presentation/MainScene/ViewModel/MainViewModel.swift index f51b94ad..c80444c3 100644 --- a/StreetDrop/StreetDrop/Presentation/MainScene/ViewModel/MainViewModel.swift +++ b/StreetDrop/StreetDrop/Presentation/MainScene/ViewModel/MainViewModel.swift @@ -31,7 +31,7 @@ final class MainViewModel: ViewModel { private let myInfoUseCase: MyInfoUseCase private let fetchingPOIUseCase: FetchingPOIUseCase private let fetchingMusicCountUseCse: FetchingMusicCountUseCase - private let fetchingMusicWithinArea: FetchingMusicWithinArea + private let fetchingMusicWithinAreaUseCase: FetchingMusicWithinAreaUseCase private let fetchingPopUpInfomationUseCase: FetchingPopUpInfomationUseCase private let postingPopUpUserReadingUseCase: PostingPopUpUserReadingUseCase @@ -43,7 +43,7 @@ final class MainViewModel: ViewModel { myInfoUseCase: MyInfoUseCase = DefaultMyInfoUseCase(), fetchingPOIUseCase: FetchingPOIUseCase = DefaultFetchingPOIUseCase(), fetchingMusicCountUseCse: FetchingMusicCountUseCase = DefaultFetchingMusicCountUseCase(), - fetchingMusicWithinArea: FetchingMusicWithinArea = DefaultFetchingMusicWithinArea(), + fetchingMusicWithinAreaUseCase: FetchingMusicWithinAreaUseCase = DefaultFetchingMusicWithinAreaUseCase(), fetchingSingleMusicUseCase: FetchingSingleMusicUseCase = DefaultFetchingSingleMusicUseCase(), fetchingPopUpInfomationUseCase: FetchingPopUpInfomationUseCase = DefaultFetchingPopUpInfomationUseCase(), postingPopUpUserReadingUseCase: PostingPopUpUserReadingUseCase = DefaultPostingPopUpUserReadingUseCase() @@ -52,7 +52,7 @@ final class MainViewModel: ViewModel { self.myInfoUseCase = myInfoUseCase self.fetchingPOIUseCase = fetchingPOIUseCase self.fetchingMusicCountUseCse = fetchingMusicCountUseCse - self.fetchingMusicWithinArea = fetchingMusicWithinArea + self.fetchingMusicWithinAreaUseCase = fetchingMusicWithinAreaUseCase self.fetchingPopUpInfomationUseCase = fetchingPopUpInfomationUseCase self.postingPopUpUserReadingUseCase = postingPopUpUserReadingUseCase self.locationManager.delegate = self @@ -237,7 +237,7 @@ private extension MainViewModel { } func fetchMusicWithArea(output: Output, disposedBag: DisposeBag) { - fetchingMusicWithinArea.execute( + fetchingMusicWithinAreaUseCase.execute( lat: self.location.coordinate.latitude, lon: self.location.coordinate.longitude, distance: userCircleRadius diff --git a/StreetDrop/StreetDrop/Presentation/MusicDropView/ViewModel/MusicDropViewModel.swift b/StreetDrop/StreetDrop/Presentation/MusicDropView/ViewModel/MusicDropViewModel.swift index bec9eba9..9ae2d85b 100644 --- a/StreetDrop/StreetDrop/Presentation/MusicDropView/ViewModel/MusicDropViewModel.swift +++ b/StreetDrop/StreetDrop/Presentation/MusicDropView/ViewModel/MusicDropViewModel.swift @@ -36,15 +36,15 @@ class MusicDropViewModel: ViewModel { var state: State = .drop private let droppingInfo: DroppingInfo - private let musicDropUseCase: MusicDropUseCase + private let dropMusicUseCase: DropMusicUseCase private let disposeBag: DisposeBag = DisposeBag() init ( droppingInfo: DroppingInfo, - musicDropUseCase: MusicDropUseCase = DefaultMusicDropUseCase() + dropMusicUseCase: DropMusicUseCase = DefaultDropMusicUseCase() ) { self.droppingInfo = droppingInfo - self.musicDropUseCase = musicDropUseCase + self.dropMusicUseCase = dropMusicUseCase } func convert(input: Input, disposedBag: RxSwift.DisposeBag) -> Output { @@ -93,7 +93,7 @@ class MusicDropViewModel: ViewModel { var comment = "" input.comment.bind { comment = $0 }.disposed(by: DisposeBag()) - self.musicDropUseCase.drop(droppingInfo: self.droppingInfo, content: comment) + self.dropMusicUseCase.drop(droppingInfo: self.droppingInfo, content: comment) .subscribe(onSuccess: { response in if !(200...299).contains(response) { output.isSuccessDrop.accept( diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/Model/Entites/MyMusic.swift b/StreetDrop/StreetDrop/Presentation/MyPage/Model/Entites/MyMusic.swift index 75296f1c..4af62085 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/Model/Entites/MyMusic.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/Model/Entites/MyMusic.swift @@ -8,7 +8,17 @@ import Foundation import RxDataSources -struct MyMusic { +struct TotalMyMusics { + let musics: [MyMusics] + let totalCount: Int +} + +struct MyMusics { + let date: String + let musics: [MyMusic] +} + +struct MyMusic: Hashable { let id: Int let userId: Int var userName: String @@ -22,33 +32,34 @@ struct MyMusic { let createdAt: String let location: String let likeCount: Int -} - -struct MyMusics { - let date: String - let musics: [MyMusic] -} - -struct TotalMyMusics { - let musics: [MyMusics] - let totalCount: Int -} - -struct MyMusicsSection { - var date: String - var items: [Item] + let isLiked: Bool + + private let identifier = UUID() - init(date: String, items: [MyMusic]) { - self.date = date - self.items = items + func hash(into hasher: inout Hasher) { + hasher.combine(identifier) + } + + static func == (lhs: MyMusic, rhs: MyMusic) -> Bool { + return lhs.identifier == rhs.identifier } } -extension MyMusicsSection: SectionModelType { - typealias Item = MyMusic +struct MyMusicsSectionType: Hashable { + let section: MyMusicsSection + let items: [MyMusic] - init(original: MyMusicsSection, items: [MyMusic]) { - self = original - self.items = items + private let identifier = UUID() + + func hash(into hasher: inout Hasher) { + hasher.combine(identifier) } + + static func == (lhs: MyMusicsSectionType, rhs: MyMusicsSectionType) -> Bool { + return lhs.identifier == rhs.identifier + } +} + +enum MyMusicsSection: Hashable { + case musics(date: String) } diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/Model/MyPageModel.swift b/StreetDrop/StreetDrop/Presentation/MyPage/Model/MyPageModel.swift deleted file mode 100644 index 9e5281f0..00000000 --- a/StreetDrop/StreetDrop/Presentation/MyPage/Model/MyPageModel.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// MyPageModel.swift -// StreetDrop -// -// Created by JoongkyuPark on 2023/07/19. -// - -import Foundation - -import RxSwift - -protocol MyPageModel { - func fetchMyDropList() -> Single - func fetchMyLikeList() -> Single - func fetchMyLevel() -> Single - func fetchMyLevelProgress() -> Single - func fetchLevelPolicy() -> Single<[LevelPolicy]> - func fetchMyDropMusic(itemID: Int) -> Single -} - -final class DefaultMyPageModel: MyPageModel { - private let repository: MyPageRepository - - init( - repository: MyPageRepository - ) { - self.repository = repository - } - - func fetchMyDropList() -> Single { - return repository.fetchMyDropList() - } - - func fetchMyLikeList() -> Single { - return repository.fetchMyLikeList() - } - - func fetchMyLevel() -> Single { - return repository.fetchMyLevel() - } - - func fetchMyLevelProgress() -> Single { - return repository.fetchMyLevelProgress() - } - - func fetchLevelPolicy() -> Single<[LevelPolicy]> { - return repository.fetchLevelPolicy() - } - - func fetchMyDropMusic(itemID: Int) -> Single { - return repository.fetchMyDropMusic(itemID: itemID) - } -} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift new file mode 100644 index 00000000..604eef90 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/FilterType.swift @@ -0,0 +1,36 @@ +// +// 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 "인기순" + } + } + + var param: String { + switch self { + case .newest: + return "RECENT" + case .oldest: + return "OLDEST" + case .mostPopular: + return "MOST_LIKED" + } + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListCell.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListCell.swift new file mode 100644 index 00000000..c1526c49 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListCell.swift @@ -0,0 +1,348 @@ +// +// MusicTableViewCell.swift +// StreetDrop +// +// Created by JoongkyuPark on 2023/07/01. +// + +import UIKit + +import SnapKit +import RxCocoa +import RxSwift + +final class MusicListCell: UITableViewCell { + static let identifier = "MusicListCell" + + private var disposeBag: DisposeBag = DisposeBag() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + configureUI() + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + updateLikeViewCornerRadius() + } + + func setData(item: MyMusic) { + albumCoverImageView.setImage(with: item.albumImageURL) + self.musicTitleLabel.text = item.song + self.singerNameLabel.text = item.singer + self.commentLabel.text = item.comment + self.locationLabel.text = item.location + self.likeLabel.text = String(item.likeCount) + updateLikeIconImage(isLiked: item.isLiked) + self.userNameLabel.text = item.userName + + if let createdDate = item.createdAt.toDate() { + let timeAgoText: String = Date().timeAgoDisplay(from: createdDate) + self.timeAgoLabel.text = timeAgoText + } + + layoutIfNeeded() + } + + // MARK: - UI + + private lazy var containerView: UIView = { + let view = UIView() + view.backgroundColor = .clear + return view + }() + + private lazy var userNameLabel: UILabel = { + let label = UILabel() + label.text = "유저" + label.textColor = .white + label.font = .pretendard(size: 14, weightName: .medium) + return label + }() + + private lazy var locationTimeAgoStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 4 + stackView.distribution = .fill + return stackView + }() + + private lazy var locationIconImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "locationBasicIcon")?.withRenderingMode(.alwaysTemplate) + imageView.tintColor = UIColor.darkPrimary_75 + return imageView + }() + + private lazy var locationLabel: UILabel = { + let label = UILabel() + label.text = "XXX구 XXX동" + label.textColor = UIColor.darkPrimary_75 + label.font = .pretendard(size: 12, weightName: .regular) + return label + }() + + private lazy var timeAgoLabel: UILabel = { + let label = UILabel() + label.text = "1초 전" + label.textColor = .gray200 + label.font = .pretendard(size: 12, weightName: .regular) + return label + }() + + private lazy var commentLabel: UILabel = { + let label = UILabel() + label.text = "코멘트" + label.textColor = .gray100 + label.font = .pretendard(size: 14, weightName: .regular) + label.numberOfLines = 4 + return label + }() + + private lazy var albumCoverImageView: UIImageView = { + let imageView = UIImageView() + imageView.backgroundColor = .gray200 + imageView.layer.cornerRadius = 8 + imageView.layer.masksToBounds = true + return imageView + }() + + private lazy var musicTitleLabel: UILabel = { + let label = UILabel() + label.text = "음악 이름" + label.textColor = .white + label.font = .pretendard(size: 12, weightName: .semiBold) + return label + }() + + private lazy var singerNameLabel: UILabel = { + let label = UILabel() + label.text = "가수 이름" + label.textColor = .gray200 + label.font = .pretendard(size: 12, weightName: .semiBold) + return label + }() + + private lazy var likeView: UIView = { + let view = UIView() + view.backgroundColor = .clear + view.layer.borderColor = UIColor.gray400.cgColor + view.layer.borderWidth = 1 + + return view + }() + + private lazy var likeIconImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "icon-heart-empty")?.withRenderingMode(.alwaysTemplate) + imageView.tintColor = .gray400 + return imageView + }() + + private lazy var likeLabel: UILabel = { + let label = UILabel() + label.text = "0" + label.textColor = .white + label.font = .pretendard(size: 12, weightName: .regular) + return label + }() +} + +// MARK: - Private Methods + +private extension MusicListCell { + + // MARK: - UI + + func configureUI() { + + // MARK: - Cell + + self.backgroundColor = UIColor.gray900 + self.selectionStyle = .none + + // MARK: - Root View + let rootView = UIView() + rootView.backgroundColor = .gray800 + rootView.roundCorners(.allCorners, radius: 20) + + contentView.addSubview(rootView) + rootView.snp.makeConstraints { + $0.top.equalToSuperview().inset(8) + $0.leading.trailing.equalToSuperview().inset(24) + $0.bottom.lessThanOrEqualToSuperview().inset(8).priority(.high) + } + + // MARK: - Container View + + rootView.addSubview(containerView) + containerView.snp.makeConstraints { + $0.top.bottom.equalToSuperview().inset(16) + $0.leading.trailing.equalToSuperview().inset(20) + } + + // MARK: - User Name Label + + containerView.addSubview(userNameLabel) + userNameLabel.snp.makeConstraints { + $0.top.leading.trailing.equalToSuperview() + $0.height.equalTo(20) + } + + // MARK: - Location TimeAgo StackView + + containerView.addSubview(locationTimeAgoStackView) + locationTimeAgoStackView.snp.makeConstraints { + $0.top.equalTo(userNameLabel.snp.bottom).offset(2) + $0.leading.equalToSuperview() + $0.height.equalTo(16) + } + + let dotLabel = UILabel() + dotLabel.text = "·" + dotLabel.textColor = .gray200 + dotLabel.textAlignment = .center + + [ + locationIconImageView, + locationLabel, + dotLabel, + timeAgoLabel + ] + .forEach { view in + locationTimeAgoStackView.addArrangedSubview(view) + } + + // MARK: - Comment Label + + containerView.addSubview(commentLabel) + commentLabel.snp.makeConstraints { + $0.top.equalTo(locationTimeAgoStackView.snp.bottom).offset(8) + $0.leading.trailing.equalToSuperview() + } + + // MARK: - Separator View + + let separatorView = UIView() + separatorView.backgroundColor = .gray600 + + containerView.addSubview(separatorView) + separatorView.snp.makeConstraints { + $0.top.equalTo(commentLabel.snp.bottom).offset(12) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(1) + } + + // MARK: - Bottom Content View + + let bottomContentView = UIView() + bottomContentView.backgroundColor = .clear + + containerView.addSubview(bottomContentView) + bottomContentView.snp.makeConstraints { + $0.top.equalTo(separatorView.snp.bottom).offset(12) + $0.leading.trailing.bottom.equalToSuperview() + $0.height.equalTo(42) + } + + // MARK: - Album Cover Image View + + bottomContentView.addSubview(albumCoverImageView) + albumCoverImageView.snp.makeConstraints { + $0.top.leading.bottom.equalToSuperview() + $0.width.equalTo(42) + } + + // MARK: - Muisc Singer View + + let musicSingerView = UIView() + musicSingerView.backgroundColor = .clear + + bottomContentView.addSubview(musicSingerView) + musicSingerView.snp.makeConstraints { + $0.top.bottom.equalToSuperview() + $0.leading.equalTo(albumCoverImageView.snp.trailing).offset(16) + } + + // MARK: - Music Title Label + + musicSingerView.addSubview(musicTitleLabel) + musicTitleLabel.snp.makeConstraints { + $0.top.equalToSuperview().inset(7) + $0.leading.trailing.equalToSuperview() + } + + // MARK: - Singer Name Label + + musicSingerView.addSubview(singerNameLabel) + singerNameLabel.snp.makeConstraints { + $0.top.equalTo(musicTitleLabel.snp.bottom).offset(2) + $0.leading.trailing.equalToSuperview() + $0.bottom.equalToSuperview().inset(7) + } + + // MARK: - Like Stack View + + bottomContentView.addSubview(likeView) + likeView.snp.makeConstraints { + $0.top.bottom.equalToSuperview().inset(7) + $0.leading.greaterThanOrEqualTo(musicSingerView.snp.trailing).offset(16) + $0.trailing.equalToSuperview() + } + + likeView.addSubview(likeIconImageView) + likeIconImageView.snp.makeConstraints { + $0.top.bottom.leading.equalToSuperview().inset(4) + $0.width.equalTo(20) + } + + likeView.addSubview(likeLabel) + likeLabel.snp.makeConstraints { + $0.top.bottom.equalToSuperview().inset(6) + $0.leading.equalTo(likeIconImageView.snp.trailing).offset(2) + $0.trailing.equalToSuperview().inset(8) + } + } + + func updateLikeViewCornerRadius() { + let labelSize = likeLabel.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: likeView.bounds.height)) + let viewHeight = likeView.bounds.height + let cornerRadius = min(viewHeight, labelSize.width + 24) / 2 + likeView.roundCorners(.allCorners, radius: cornerRadius) + } + + func updateLikeIconImage(isLiked: Bool) { + let image: UIImage? = isLiked ? + .init(named: "icon-heart-fill") : + .init(named: "icon-heart-empty") + likeIconImageView.image = image?.withRenderingMode(.alwaysTemplate) + likeIconImageView.tintColor = isLiked ? .main_100 : .gray400 + } +} + +//MARK: - for canvas +import SwiftUI +struct UIViewPreview: UIViewRepresentable { + let view: View + + init(_ builder: @escaping () -> View) { + view = builder() + } + + func makeUIView(context: Context) -> UIView { + return view + } + + func updateUIView(_ view: UIView, context: Context) { + view.setContentHuggingPriority(.defaultHigh, for: .horizontal) + view.setContentHuggingPriority(.defaultHigh, for: .vertical) + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListSectionHeaderView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListSectionHeaderView.swift similarity index 87% rename from StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListSectionHeaderView.swift rename to StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListSectionHeaderView.swift index 9765ebb7..36b585f7 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicListSectionHeaderView.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListSectionHeaderView.swift @@ -21,6 +21,7 @@ final class MusicListSectionHeaderView: UITableViewHeaderFooterView { override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) + self.configureUI() } @@ -38,12 +39,7 @@ extension MusicListSectionHeaderView { // MARK: - UI func configureUI() { - - // MARK: - View - - let backgroundView = UIView() - backgroundView.backgroundColor = UIColor.gray900 - self.backgroundView = backgroundView + backgroundColor = UIColor.gray900 // MARK: - Date Label diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListTableView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListTableView.swift new file mode 100644 index 00000000..83ec7fe1 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MusicListTableView.swift @@ -0,0 +1,21 @@ +// +// MusicListTableView.swift +// StreetDrop +// +// Created by thoonk on 7/12/24. +// + +import UIKit + +final class MusicListTableView: UITableView { + override var intrinsicContentSize: CGSize { + layoutIfNeeded() + return contentSize + } + + override var contentSize: CGSize { + didSet { + invalidateIntrinsicContentSize() + } + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MyPageType.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MyPageType.swift new file mode 100644 index 00000000..6c0981e2 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicList/MyPageType.swift @@ -0,0 +1,13 @@ +// +// MyPageType.swift +// StreetDrop +// +// Created by thoonk on 11/8/23. +// + +import Foundation + +enum MyMusicType { + case drop + case like +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicTableViewCell.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicTableViewCell.swift deleted file mode 100644 index 9806dd0f..00000000 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MusicTableViewCell.swift +++ /dev/null @@ -1,303 +0,0 @@ -// -// MusicTableViewCell.swift -// StreetDrop -// -// Created by JoongkyuPark on 2023/07/01. -// - -import UIKit - -import SnapKit -import RxCocoa -import RxSwift - -final class MusicTableViewCell: UITableViewCell { - static let identifier = "MusicTableViewCell" - private var disposeBag: DisposeBag = DisposeBag() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.configureUI() - } - - @available(*, unavailable) - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setData(item: MyMusic) { - albumCoverImageView.setImage(with: item.albumImageURL) - self.musicTitleLabel.text = item.song - self.singerNameLabel.text = item.singer - self.commentLabel.text = item.comment - self.locationLabel.text = item.location - self.likeLabel.text = String(item.likeCount) - } - - // MARK: - UI - - private lazy var containerStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 16 - stackView.alignment = .top - return stackView - }() - - private lazy var albumCoverImageView: UIImageView = { - let imageView = UIImageView() - imageView.backgroundColor = .gray - imageView.layer.cornerRadius = 10 - imageView.layer.masksToBounds = true - return imageView - }() - - private lazy var infoStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.spacing = 8 - return stackView - }() - - private lazy var musicSingerStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 8 - stackView.alignment = .center - stackView.distribution = .fill - return stackView - }() - - private lazy var musicTitleLabel: UILabel = { - let label = UILabel() - label.text = "음악 이름" - label.textColor = .white - label.font = .pretendard(size: 14, weightName: .bold) - return label - }() - - private lazy var singerNameLabel: UILabel = { - let label = UILabel() - label.text = "가수 이름" - label.textColor = .gray200 - label.font = .pretendard(size: 14, weightName: .regular) - return label - }() - - private lazy var commentLabel: UILabel = { - let label = UILabel() - label.text = "코멘트" - label.textColor = .gray100 - label.font = .pretendard(size: 16, weightName: .medium) - label.numberOfLines = 0 - return label - }() - - private lazy var locaitonLikeStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 0 - stackView.distribution = .fill - return stackView - }() - - private lazy var locationIconImageView: UIImageView = { - let imageView = UIImageView() - imageView.image = UIImage(named: "locationBasicIcon")?.withRenderingMode(.alwaysTemplate) - imageView.tintColor = UIColor.darkPrimary_75 - return imageView - }() - - private lazy var locationLabel: UILabel = { - let label = UILabel() - label.text = "XXX구 XXX동" - label.textColor = UIColor.darkPrimary_75 - label.font = .pretendard(size: 12, weightName: .regular) - return label - }() - - private lazy var likeIconImageView: UIImageView = { - let imageView = UIImageView() - imageView.image = UIImage(named: "likeFillIcon")?.withRenderingMode(.alwaysTemplate) - imageView.tintColor = UIColor.darkPrimary_75 - return imageView - }() - - private lazy var likeLabel: UILabel = { - let label = UILabel() - label.text = "0" - label.textColor = UIColor.darkPrimary_75 - label.font = .pretendard(size: 12, weightName: .regular) - return label - }() - - private lazy var separatorView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.gray700 - return view - }() -} - -private extension MusicTableViewCell { - - // MARK: - UI - - func configureUI() { - - // MARK: - Cell - - self.backgroundColor = UIColor.gray900 - self.selectionStyle = .none - - // MARK: - Container StackView - - self.addSubview(self.containerStackView) - self.containerStackView.snp.makeConstraints { make in - make.top.bottom.leading.trailing.equalToSuperview().inset(24) - } - - // MARK: - Album Cover ImageView - - self.containerStackView.addArrangedSubview(albumCoverImageView) - self.albumCoverImageView.snp.makeConstraints { make in - make.width.height.equalTo(48) - } - - // MARK: - Info StackView - - self.containerStackView.addArrangedSubview(infoStackView) - - // MARK: - Music Singer StackView - - self.infoStackView.addArrangedSubview(musicSingerStackView) - self.musicSingerStackView.snp.makeConstraints { make in - make.trailing.equalToSuperview() - } - - // MARK: - Muisc Title Label - - self.musicSingerStackView.addArrangedSubview(musicTitleLabel) - - // MARK: - Singer Name Label - - self.musicSingerStackView.addArrangedSubview(singerNameLabel) - - self.musicSingerStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.translatesAutoresizingMaskIntoConstraints = false - spacerView.backgroundColor = UIColor.clear - spacerView.widthAnchor.constraint(equalToConstant: 1).isActive = true - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - return spacerView - }() - ) - - self.musicSingerStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.backgroundColor = UIColor.clear - return spacerView - }() - ) - - // MARK: - Comment Label - - self.infoStackView.addArrangedSubview(commentLabel) - - // MARK: - Location Like StackView - - self.infoStackView.addArrangedSubview(locaitonLikeStackView) - self.locaitonLikeStackView.snp.makeConstraints { make in - make.trailing.equalToSuperview() - } - - // MARK: - Location Icon ImageView - - self.locaitonLikeStackView.addArrangedSubview(locationIconImageView) - self.locationIconImageView.snp.makeConstraints { make in - make.width.height.equalTo(16) - } - - // MARK: - Location Label - - self.locaitonLikeStackView.addArrangedSubview(locationLabel) - - // MARK: - Like Icon ImageView - - self.locaitonLikeStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.translatesAutoresizingMaskIntoConstraints = false - spacerView.backgroundColor = UIColor.clear - spacerView.widthAnchor.constraint(equalToConstant: 8).isActive = true - return spacerView - }() - ) - self.locaitonLikeStackView.addArrangedSubview(likeIconImageView) - self.likeIconImageView.snp.makeConstraints { make in - make.width.height.equalTo(16) - } - - // MARK: - Like Label - - self.locaitonLikeStackView.addArrangedSubview(likeLabel) - - self.locaitonLikeStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.translatesAutoresizingMaskIntoConstraints = false - spacerView.backgroundColor = UIColor.clear - spacerView.widthAnchor.constraint(equalToConstant: 1).isActive = true - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - return spacerView - }() - ) - - self.locaitonLikeStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.backgroundColor = UIColor.clear - return spacerView - }() - ) - - // MARK: - Separator View - - self.addSubview(separatorView) - self.separatorView.snp.makeConstraints { make in - make.top.equalTo(self.snp.bottom) - make.leading.trailing.equalToSuperview() - make.height.equalTo(1) - } - } -} - -//MARK: - for canvas -import SwiftUI -struct UIViewPreview: UIViewRepresentable { - let view: View - - init(_ builder: @escaping () -> View) { - view = builder() - } - - func makeUIView(context: Context) -> UIView { - return view - } - - func updateUIView(_ view: UIView, context: Context) { - view.setContentHuggingPriority(.defaultHigh, for: .horizontal) - view.setContentHuggingPriority(.defaultHigh, for: .vertical) - } -} - -@available(iOS 13.0.0, *) -struct MusicTableViewCellPreview: PreviewProvider{ - static var previews: some View { - UIViewPreview { - return MusicTableViewCell() - } - .previewLayout(.fixed(width: 327, height: 92)) - } -} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageType.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageType.swift deleted file mode 100644 index d3b5b64b..00000000 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageType.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// MyPageType.swift -// StreetDrop -// -// Created by thoonk on 11/8/23. -// - -import Foundation - -enum MyPageType: Int { - case dropMusic = 100 - case likeMusic = 101 -} - -typealias MusicInfo = (type: MyPageType, itemID: Int) diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift index 2464afb9..898277c7 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/MyPageViewController.swift @@ -14,19 +14,23 @@ import RxSwift import SnapKit final class MyPageViewController: UIViewController, Toastable, Alertable { - typealias DataSource = RxTableViewSectionedReloadDataSource + fileprivate typealias MusicDataSource = UITableViewDiffableDataSource - private var stickyTapListStackView: UIStackView? + private var stickyTapBarView: UIView? private var stickyTopDimmedView: UIView? - private lazy var dropMusicDataSource: DataSource = configureDataSource() - private lazy var likeMusicDataSource: DataSource = configureDataSource() + private lazy var musicDataSource: MusicDataSource = configureMusicDataSource() private var viewModel: MyPageViewModel private let viewWillAppearEvent = PublishRelay() + private let listTypeTapEvent = BehaviorRelay(value: .drop) private let levelPolicyTapEvent = PublishRelay() - private let selectedMusicEvent = PublishRelay() + private let selectedMusicEvent = PublishRelay() private let disposeBag = DisposeBag() + private let totalMusicsCountRelay: ReplayRelay = .create(bufferSize: 1) + private let selectedFilterTypeEvent: BehaviorRelay = .init(value: .newest) + + // MARK: - Init init(viewModel: MyPageViewModel = MyPageViewModel()) { self.viewModel = viewModel @@ -46,16 +50,11 @@ final class MyPageViewController: UIViewController, Toastable, Alertable { self.bindViewModel() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - self.viewWillAppearEvent.accept(Void()) - } - // MARK: - UI + private lazy var scrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.backgroundColor = UIColor.gray900 - scrollView.delegate = self return scrollView }() @@ -146,79 +145,27 @@ final class MyPageViewController: UIViewController, Toastable, Alertable { private lazy var levelUpGuideView = LevelUpGuideView() - private lazy var tapListStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 8 - stackView.alignment = .bottom - return stackView - }() - - private lazy var dropTapButton: UIButton = { - let button = UIButton() - button.setTitle("드랍", for: .normal) - button.setTitleColor(.white, for: .normal) - button.setTitleColor(.lightGray, for: .highlighted) - button.titleLabel?.font = .pretendard(size: 20, weightName: .bold) - return button - }() - - private lazy var likeTapButton: UIButton = { - let button = UIButton() - button.setTitle("좋아요", for: .normal) - button.setTitleColor(UIColor.gray400, for: .normal) - button.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) - button.titleLabel?.font = .pretendard(size: 20, weightName: .bold) - return button - }() - - private lazy var dropCountLabel: UILabel = { - let label = UILabel() - label.text = "전체 0개" - label.textColor = UIColor.gray400 - label.font = .pretendard(size: 14, weightName: .regular) - return label - }() - - private lazy var likeCountLabel: UILabel = { - let label = UILabel() - label.text = "전체 0개" - label.textColor = UIColor.gray400 - label.font = .pretendard(size: 14, weightName: .regular) - label.isHidden = true - return label - }() + private lazy var tapBarView: UIView = createTapBarView(with: .drop) - private lazy var dropMusicListTableView: MusicListTableView = { - let tableView = MusicListTableView() - tableView.backgroundColor = .gray900 + private lazy var musicListTableView: MusicListTableView = { + let tableView = MusicListTableView(frame: .zero, style: .grouped) tableView.isScrollEnabled = false + tableView.backgroundColor = .clear tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 100 - tableView.register(MusicTableViewCell.self, forCellReuseIdentifier: MusicTableViewCell.identifier) - tableView.register(MusicListSectionHeaderView.self, forHeaderFooterViewReuseIdentifier: MusicListSectionHeaderView.identifier) + tableView.estimatedRowHeight = 258 + tableView.delegate = self tableView.sectionFooterHeight = 0 - tableView.tableFooterView = UIView() - tableView.tag = MyPageType.dropMusic.rawValue - tableView.rx.setDelegate(self) - .disposed(by: disposeBag) - return tableView - }() - - private lazy var likeMusicListTableView: MusicListTableView = { - let tableView = MusicListTableView() - tableView.backgroundColor = .gray900 - tableView.isHidden = true - tableView.isScrollEnabled = false - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 100 - tableView.register(MusicTableViewCell.self, forCellReuseIdentifier: MusicTableViewCell.identifier) - tableView.register(MusicListSectionHeaderView.self, forHeaderFooterViewReuseIdentifier: MusicListSectionHeaderView.identifier) - tableView.sectionFooterHeight = 0 - tableView.tableFooterView = UIView() - tableView.tag = MyPageType.likeMusic.rawValue - tableView.rx.setDelegate(self) - .disposed(by: disposeBag) + tableView.separatorStyle = .none + + tableView.register( + MusicListCell.self, + forCellReuseIdentifier: MusicListCell.identifier + ) + tableView.register( + MusicListSectionHeaderView.self, + forHeaderFooterViewReuseIdentifier: MusicListSectionHeaderView.identifier + ) + return tableView }() @@ -235,6 +182,8 @@ final class MyPageViewController: UIViewController, Toastable, Alertable { private lazy var bottomDimmedView: UIView = self.createDimmedView(isFromTop: false) } +// MARK: - UI Methods + private extension MyPageViewController { // MARK: - UI @@ -368,50 +317,20 @@ private extension MyPageViewController { // MARK: - Tap List StackView - self.containerView.addSubview(tapListStackView) - self.tapListStackView.snp.makeConstraints { make in + self.containerView.addSubview(tapBarView) + self.tapBarView.snp.makeConstraints { make in make.top.equalTo(levelUpGuideView.snp.bottom).offset(24) - make.leading.trailing.equalToSuperview().inset(24) + make.leading.trailing.equalToSuperview() } + + // MARK: - Music List CollectionView - // MARK: - Drop Tap Button - - self.tapListStackView.addArrangedSubview(dropTapButton) - - // MARK: - Like Tap Button - - self.tapListStackView.addArrangedSubview(likeTapButton) - - // MARK: - Count Label - - self.tapListStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.translatesAutoresizingMaskIntoConstraints = false - spacerView.backgroundColor = UIColor.clear - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - return spacerView - }() - ) - - self.tapListStackView.addArrangedSubview(dropCountLabel) - - // MARK: - Drop Music List TableView - - self.containerView.addSubview(dropMusicListTableView) - self.dropMusicListTableView.snp.makeConstraints { make in - make.top.equalTo(tapListStackView.snp.bottom).offset(8) - make.leading.trailing.bottom.equalToSuperview() - } - - // MARK: - Like Music List TableView - - self.containerView.addSubview(likeMusicListTableView) - self.likeMusicListTableView.snp.makeConstraints { make in - make.top.equalTo(tapListStackView.snp.bottom).offset(8) - make.leading.trailing.bottom.equalToSuperview() + containerView.addSubview(musicListTableView) + musicListTableView.snp.makeConstraints { + $0.top.equalTo(tapBarView.snp.bottom).offset(16) + $0.leading.trailing.bottom.equalToSuperview() } - + // MARK: - Scroll To Top Button self.view.addSubview(scrollToTopButton) @@ -444,120 +363,119 @@ private extension MyPageViewController { return dimmedView } - func createTapListStackView() -> UIStackView { - let newStackView = UIStackView() - newStackView.axis = .horizontal - newStackView.spacing = 8 - newStackView.alignment = .bottom - newStackView.backgroundColor = UIColor.gray900 + func createTapBarView(with type: MyMusicType) -> UIView { + let tabBarView = UIView() + tabBarView.backgroundColor = .gray900 - let newDropButton = UIButton() - newDropButton.setTitle("드랍", for: .normal) - newDropButton.titleLabel?.font = .pretendard(size: 20, weightName: .bold) + let tapListView: TapListView = .init() + tapListView.updateTapListUI(by: type) - let newLikeButton = UIButton() - newLikeButton.setTitle("좋아요", for: .normal) - newLikeButton.titleLabel?.font = .pretendard(size: 20, weightName: .bold) + let musicListFilterView: MusicListFilterView = .init() - if self.dropMusicListTableView.isHidden { - newDropButton.setTitleColor(UIColor.gray400, for: .normal) - newDropButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) - - newLikeButton.setTitleColor(.white, for: .normal) - newLikeButton.setTitleColor(.lightGray, for: .highlighted) - } else { - newDropButton.setTitleColor(.white, for: .normal) - newDropButton.setTitleColor(.lightGray, for: .highlighted) - - newLikeButton.setTitleColor(UIColor.gray400, for: .normal) - newLikeButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + let separatorView = UIView() + separatorView.backgroundColor = .gray600 + + tabBarView.addSubview(tapListView) + tapListView.snp.makeConstraints { + $0.top.equalToSuperview() + $0.leading.trailing.equalToSuperview().inset(24) + $0.height.equalTo(44) } - let newLabel = UILabel() - newLabel.textColor = UIColor.gray400 - newLabel.font = .pretendard(size: 14, weightName: .regular) - if self.dropMusicListTableView.isHidden { - newLabel.text = likeCountLabel.text - } else { - newLabel.text = dropCountLabel.text + tabBarView.addSubview(musicListFilterView) + musicListFilterView.snp.makeConstraints { + $0.top.equalTo(tapListView.snp.bottom) + $0.leading.trailing.bottom .equalToSuperview() + $0.height.equalTo(44) } - newStackView.addArrangedSubview(newDropButton) - newStackView.addArrangedSubview(newLikeButton) - newStackView.addArrangedSubview( - { - let spacerView = UIView() - spacerView.translatesAutoresizingMaskIntoConstraints = false - spacerView.backgroundColor = UIColor.clear - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - return spacerView - }() - ) - newStackView.addArrangedSubview(newLabel) + tabBarView.addSubview(separatorView) + separatorView.snp.makeConstraints { + $0.leading.trailing.bottom.equalToSuperview() + $0.height.equalTo(1) + } - bindTapButtonAction(dropTapButton: newDropButton, likeTapButton: newLikeButton) + totalMusicsCountRelay + .bind(to: musicListFilterView.rx.setMusicCountText) + .disposed(by: disposeBag) + + bindTapButtonAction(in: tapListView) + bindFilterButtonAction(in: musicListFilterView) - return newStackView + return tabBarView } - // MARK: - Action Binding - - private func bindTapButtonAction(dropTapButton: UIButton, likeTapButton: UIButton) { - dropTapButton.rx.tap - .subscribe(onNext: { [weak self] in - guard let self = self else { return } - self.dropMusicListTableView.isHidden = false - self.likeMusicListTableView.isHidden = true - - self.tapListStackView.removeArrangedSubview(self.likeCountLabel) - self.likeCountLabel.isHidden = true - self.tapListStackView.addArrangedSubview(self.dropCountLabel) - self.dropCountLabel.isHidden = false - - dropTapButton.setTitleColor(.white, for: .normal) - dropTapButton.setTitleColor(.lightGray, for: .highlighted) - self.dropTapButton.setTitleColor(.white, for: .normal) - self.dropTapButton.setTitleColor(.lightGray, for: .highlighted) - likeTapButton.setTitleColor(UIColor.gray400, for: .normal) - likeTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) - self.likeTapButton.setTitleColor(UIColor.gray400, for: .normal) - self.likeTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + func updateLevelupGuideViewConstraints(by isShow: Bool) { + if isShow == false { + if levelUpGuideView.isDescendant(of: view) { + levelUpGuideView.removeFromSuperview() - if self.scrollView.contentOffset.y > 343 { - self.scrollView.setContentOffset(CGPoint(x: 0, y: 343), animated: true) + tapBarView.snp.remakeConstraints { make in + make.top.equalTo(levelImageView.snp.bottom).offset(24) + make.leading.trailing.equalToSuperview() } - }) + } + } + } + + func updateScrollOffset() { + if scrollView.contentOffset.y > 343 { + scrollView.setContentOffset(CGPoint(x: 0, y: 343), animated: true) + } + } +} + +// MARK: - Binding Methods + +private extension MyPageViewController { + func bindTapButtonAction(in tapListView: TapListView) { + tapListView.rx.onDropTap + .throttle(.seconds(2), scheduler: MainScheduler.instance) + .bind(with: self) { owner, _ in + owner.listTypeTapEvent.accept(.drop) + owner.updateScrollOffset() + } .disposed(by: disposeBag) - likeTapButton.rx.tap - .subscribe(onNext: { [weak self] in - guard let self = self else { return } - self.dropMusicListTableView.isHidden = true - self.likeMusicListTableView.isHidden = false - - self.tapListStackView.removeArrangedSubview(self.dropCountLabel) - self.dropCountLabel.isHidden = true - self.tapListStackView.addArrangedSubview(self.likeCountLabel) - self.likeCountLabel.isHidden = false - - dropTapButton.setTitleColor(UIColor.gray400, for: .normal) - dropTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) - self.dropTapButton.setTitleColor(UIColor.gray400, for: .normal) - self.dropTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) - likeTapButton.setTitleColor(.white, for: .normal) - likeTapButton.setTitleColor(.lightGray, for: .highlighted) - self.likeTapButton.setTitleColor(.white, for: .normal) - self.likeTapButton.setTitleColor(.lightGray, for: .highlighted) + tapListView.rx.onLikeTap + .throttle(.seconds(2), scheduler: MainScheduler.instance) + .bind(with: self) { owner, _ in + owner.listTypeTapEvent.accept(.like) + owner.updateScrollOffset() + } + .disposed(by: disposeBag) + + listTypeTapEvent + .bind { type in + tapListView.updateTapListUI(by: type) + } + .disposed(by: disposeBag) + } + + func bindFilterButtonAction(in musicListFilterView: MusicListFilterView) { + musicListFilterView.rx.onSortFilterTap + .withLatestFrom(selectedFilterTypeEvent) + .bind(with: self) { owner, type in + owner.showFilteringOptionsModal(with: type) + } + .disposed(by: disposeBag) + + musicListFilterView.rx.onRegionFilterTap + .bind(with: self) { owner, _ in - if self.scrollView.contentOffset.y > 343 { - self.scrollView.setContentOffset(CGPoint(x: 0, y: 343), animated: true) - } - }) + } + .disposed(by: disposeBag) + + selectedFilterTypeEvent + .bind(to: musicListFilterView.rx.setSortButtonText) .disposed(by: disposeBag) } - private func bindAction() { - bindTapButtonAction(dropTapButton: self.dropTapButton, likeTapButton: self.likeTapButton) + func bindAction() { + rx.viewWillAppear + .mapVoid() + .bind(to: viewWillAppearEvent) + .disposed(by: disposeBag) scrollToTopButton.rx.tap .bind{ [weak self] in @@ -591,31 +509,33 @@ private extension MyPageViewController { .bind(to: levelPolicyTapEvent) .disposed(by: disposeBag) - dropMusicListTableView.rx.itemSelected + musicListTableView.rx.itemSelected .throttle(.seconds(2), scheduler: MainScheduler.instance) .bind(with: self) { owner, indexPath in - let itemID = owner.viewModel.myDropMusicList[indexPath.section][indexPath.row].id - owner.selectedMusicEvent.accept((MyPageType.dropMusic ,itemID)) + guard let item = owner.musicDataSource.itemIdentifier(for: indexPath) else { return } + owner.selectedMusicEvent.accept(item.id) } .disposed(by: disposeBag) - likeMusicListTableView.rx.itemSelected - .throttle(.seconds(2), scheduler: MainScheduler.instance) - .bind(with: self) { owner, indexPath in - let itemID = owner.viewModel.myLikeMusicList[indexPath.section][indexPath.row].id - owner.selectedMusicEvent.accept((MyPageType.likeMusic ,itemID)) + typealias ScrollViewState = (contentOffset: CGPoint, type: MyMusicType) + + scrollView.rx.contentOffset + .withLatestFrom(listTypeTapEvent) { (contentOffset: $0, type: $1) } + .bind(with: self) { owner, state in + owner.handleScrollEvent(contentOffset: state.contentOffset, type: state.type) } .disposed(by: disposeBag) } - - // MARK: - Data Binding - - private func bindViewModel() { + + func bindViewModel() { let input = MyPageViewModel.Input( - viewWillAppearEvent: self.viewWillAppearEvent, - levelPolicyTapEvent: levelPolicyTapEvent, - selectedMusicEvent: selectedMusicEvent + viewWillAppearEvent: viewWillAppearEvent.asObservable(), + listTypeTapEvent: listTypeTapEvent.asObservable(), + levelPolicyTapEvent: levelPolicyTapEvent.asObservable(), + selectedMusicEvent: selectedMusicEvent.asObservable(), + selectedFilterTypeEvent: selectedFilterTypeEvent.asObservable() ) + let output = viewModel.convert(input: input, disposedBag: disposeBag) output.levelName @@ -637,24 +557,14 @@ private extension MyPageViewController { }) .disposed(by: disposeBag) - output.myDropMusicsSections - .bind(to: dropMusicListTableView.rx.items(dataSource: dropMusicDataSource)) - .disposed(by: disposeBag) - - output.myLikeMusicsSections - .bind(to: likeMusicListTableView.rx.items(dataSource: likeMusicDataSource)) - .disposed(by: disposeBag) - - output.totalDropMusicsCount - .bind(onNext: { [weak self] count in - self?.dropCountLabel.text = "전체 \(count)개" - }) + output.myMusicsSections + .bind(with: self) { owner, sections in + owner.displayMusicList(sections) + } .disposed(by: disposeBag) - output.totalLikeMusicsCount - .bind(onNext: { [weak self] count in - self?.likeCountLabel.text = "전체 \(count)개" - }) + output.totalMusicsCount + .bind(to: totalMusicsCountRelay) .disposed(by: disposeBag) output.pushCommunityView @@ -713,154 +623,136 @@ private extension MyPageViewController { } } -// MARK: - ScrollView Delegate +// MARK: - ScrollView Methods -extension MyPageViewController: UIScrollViewDelegate { - func scrollViewDidScroll(_ scrollView: UIScrollView) { +private extension MyPageViewController { + func handleScrollEvent(contentOffset: CGPoint, type: MyMusicType) { // 맨 위로 스크롤하기 버튼 활성화 - if scrollView == self.scrollView { - let offsetY = scrollView.contentOffset.y - if offsetY > 400 { - scrollToTopButton.isHidden = false - } else { - scrollToTopButton.isHidden = true - } + let offsetY = contentOffset.y + if offsetY > 400 { + scrollToTopButton.isHidden = false + } else { + scrollToTopButton.isHidden = true } // 드랍, 좋아요 탭 상단에 고정시키기 - if scrollView.contentOffset.y > 343 { - if self.stickyTapListStackView == nil { - self.stickyTapListStackView = createTapListStackView() + if contentOffset.y > 500 { + if self.stickyTapBarView == nil { + self.stickyTapBarView = createTapBarView(with: type) self.stickyTopDimmedView = createDimmedView(isFromTop: true) - guard let stickyTapListStackView = stickyTapListStackView else { return } - guard let stickyDimmedView = stickyTopDimmedView else { return } + guard let stickyTapBarView, + let stickyDimmedView = stickyTopDimmedView + else { return } - self.view.addSubview(stickyTapListStackView) - stickyTapListStackView.snp.makeConstraints { make in + self.view.addSubview(stickyTapBarView) + stickyTapBarView.snp.makeConstraints { make in make.top.equalTo(self.view.safeAreaLayoutGuide) - make.leading.trailing.equalTo(self.view.safeAreaLayoutGuide).inset(24) + make.leading.trailing.equalTo(self.view.safeAreaLayoutGuide) } self.view.addSubview(stickyDimmedView) stickyDimmedView.snp.makeConstraints { make in - make.top.equalTo(stickyTapListStackView.snp.bottom) + make.top.equalTo(stickyTapBarView.snp.bottom) make.height.equalTo(24) make.leading.trailing.equalTo(self.view.safeAreaLayoutGuide) } } } else { - if let stickyTapListStackView = self.stickyTapListStackView, + if let stickyTapBarView, let stickyDimmedView = self.stickyTopDimmedView { - stickyTapListStackView.removeFromSuperview() + stickyTapBarView.removeFromSuperview() stickyDimmedView.removeFromSuperview() } - self.stickyTapListStackView = nil + self.stickyTapBarView = nil self.stickyTopDimmedView = nil } } } -// MARK: - TableView Delegate - -extension MyPageViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return 32 - } - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - if let type = MyPageType(rawValue: tableView.tag) { - return configureHeaderView( - type: type, - tableView: tableView, - section: section - ) - } else { - return nil - } - } -} - // MARK: - Private Methods private extension MyPageViewController { - func configureDataSource() -> DataSource { - return DataSource( - configureCell: { _, tableView, indexPath, item in - guard let cell = tableView.dequeueReusableCell(withIdentifier: MusicTableViewCell.identifier, for: indexPath) as? MusicTableViewCell else { return UITableViewCell() } - cell.setData(item: item) - return cell - }) + func configureMusicDataSource() -> MusicDataSource { + return MusicDataSource(tableView: musicListTableView, cellProvider: { tableView, indexPath, item -> UITableViewCell? in + guard let cell = tableView.dequeueReusableCell( + withIdentifier: MusicListCell.identifier, + for: indexPath + ) as? MusicListCell else { return nil } + + cell.setData(item: item) + + return cell + }) } - func configureHeaderView( - type: MyPageType, - tableView: UITableView, - section: Int - ) -> UIView? { - var dataSource: DataSource - - switch type { - case .dropMusic: - dataSource = dropMusicDataSource - case .likeMusic: - dataSource = likeMusicDataSource + func displayMusicList(_ sectionTypes: [MyMusicsSectionType]) { + var snapshot = NSDiffableDataSourceSnapshot() + + sectionTypes.forEach { sectionType in + snapshot.appendSections([sectionType.section]) + snapshot.appendItems(sectionType.items, toSection: sectionType.section) } - guard let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: MusicListSectionHeaderView.identifier) as? MusicListSectionHeaderView - else { return UIView() } + musicDataSource.apply(snapshot, animatingDifferences: true) + } + + func showFilteringOptionsModal(with selectedType: FilterType) { + let newestOption = ModalOption( + icon: UIImage(named: "icon-check"), + title: FilterType.newest.title, + acton: filterMusicList(by: .newest), + isSelected: selectedType == .newest + ) - let sectionData = dataSource[section] - headerView.setData(date: sectionData.date) - return headerView + let oldestOption = ModalOption( + icon: UIImage(named: "icon-check"), + title: FilterType.oldest.title, + acton: filterMusicList(by: .oldest), + isSelected: selectedType == .oldest + ) + + let mostPopularOption = ModalOption( + icon: UIImage(named: "icon-check"), + 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 updateLevelupGuideViewConstraints(by isShow: Bool) { - if isShow == false { - if levelUpGuideView.isDescendant(of: view) { - levelUpGuideView.removeFromSuperview() - - tapListStackView.snp.remakeConstraints { make in - make.top.equalTo(levelImageView.snp.bottom).offset(24) - make.leading.trailing.equalToSuperview().inset(24) - } - } + func filterMusicList(by type: FilterType) -> UIAction { + return UIAction { [weak self] _ in + self?.selectedFilterTypeEvent.accept(type) + self?.navigationController?.dismiss(animated: true) } } } -// MARK: - 커스텀 테이블뷰 +// MARK: - UITableViewDelegate -private final class MusicListTableView: UITableView { - override var contentSize:CGSize { - didSet { - invalidateIntrinsicContentSize() +extension MyPageViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let section = self.musicDataSource.snapshot().sectionIdentifiers[safe: section] + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: MusicListSectionHeaderView.identifier) as? MusicListSectionHeaderView + + if case let .musics(date) = section { + headerView?.setData(date: date) } + + return headerView } - override var intrinsicContentSize: CGSize { - layoutIfNeeded() - return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) - } -} - - -//MARK: - for canvas -import SwiftUI -struct MyPageViewControllerRepresentable: UIViewControllerRepresentable { - typealias UIViewControllerType = MyPageViewController - - func makeUIViewController(context: Context) -> MyPageViewController { - return MyPageViewController() - } - - func updateUIViewController(_ uiViewController: MyPageViewController, context: Context) { - } -} - -@available(iOS 13.0.0, *) -struct MyPageViewControllerPreview: PreviewProvider { - static var previews: some View { - MyPageViewControllerRepresentable() + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0 } } diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift new file mode 100644 index 00000000..2c6922d5 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/MusicListFilterView.swift @@ -0,0 +1,116 @@ +// +// MusicListFilterView.swift +// StreetDrop +// +// Created by thoonk on 7/18/24. +// + +import UIKit + +import RxSwift + +final class MusicListFilterView: UIView { + + fileprivate let musicCountLabel: UILabel = { + let label = UILabel() + label.text = "총 0개" + label.textColor = .gray200 + label.font = .pretendard(size: 14, weightName: .regular) + return label + }() + + fileprivate let sortFilterButton: UIButton = { + let button = UIButton() + button.setTitle("최신순", for: .normal) + button.setTitleColor(.gray200, for: .normal) + button.titleLabel?.font = .pretendard(size: 14, weightName: .regular) + let image = UIImage(named: "icon-arrow-down")?.withRenderingMode(.alwaysTemplate) + button.setImage(image, for: .normal) + button.tintColor = .gray150 + button.semanticContentAttribute = .forceRightToLeft + + return button + }() + + fileprivate let regionFilterButton: UIButton = { + let button = UIButton() + button.setTitle("필터", for: .normal) + button.setTitleColor(.primary400, for: .normal) + button.titleLabel?.font = .pretendard(size: 14, weightName: .regular) + button.tintColor = .primary400 + + let image = UIImage(named: "icon-filter")?.withRenderingMode(.alwaysTemplate) + button.setImage(image, for: .normal) + button.semanticContentAttribute = .forceRightToLeft + button.layer.borderColor = UIColor.primary400.cgColor + button.layer.borderWidth = 1.0 + button.roundCorners(.allCorners, radius: 12) + button.contentEdgeInsets = .init(top: 6, left: 8, bottom: 6, right: 4) + + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + configureUI() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Private Methods + +private extension MusicListFilterView { + func configureUI() { + backgroundColor = .gray900 + + addSubview(musicCountLabel) + musicCountLabel.snp.makeConstraints { + $0.top.equalToSuperview().inset(8) + $0.bottom.equalToSuperview().inset(12) + $0.leading.equalToSuperview().inset(24) + } + + addSubview(regionFilterButton) + regionFilterButton.snp.makeConstraints { + $0.top.bottom.equalTo(musicCountLabel) + $0.trailing.equalToSuperview().inset(24) + } + + addSubview(sortFilterButton) + sortFilterButton.snp.makeConstraints { + $0.top.bottom.equalTo(musicCountLabel) + $0.trailing.equalTo(regionFilterButton.snp.leading).offset(-16) + } + } +} + +// MARK: - MusicListFilterView + Rx + +extension Reactive where Base: MusicListFilterView { + var setMusicCountText: Binder { + Binder(base) { base, totalCount in + base.musicCountLabel.text = "총 \(totalCount)개" + } + } + + 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) + } + + var onRegionFilterTap: Observable { + base.sortFilterButton.rx.tap.mapVoid() + .throttle(.seconds(2), scheduler: MainScheduler.instance) + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/TapListView.swift b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/TapListView.swift new file mode 100644 index 00000000..fc8e1785 --- /dev/null +++ b/StreetDrop/StreetDrop/Presentation/MyPage/View/TabBar/TapListView.swift @@ -0,0 +1,102 @@ +// +// TapListView.swift +// StreetDrop +// +// Created by thoonk on 7/18/24. +// + +import UIKit + +import RxSwift + +final class TapListView: UIView { + + fileprivate let dropTapButton: UIButton = { + let button = UIButton() + button.setTitle("드랍", for: .normal) + button.setTitleColor(.white, for: .normal) + button.setTitleColor(.lightGray, for: .highlighted) + button.titleLabel?.font = .pretendard(size: 20, weightName: .bold) + return button + }() + + fileprivate let likeTapButton: UIButton = { + let button = UIButton() + button.setTitle("좋아요", for: .normal) + button.setTitleColor(UIColor.gray400, for: .normal) + button.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + button.titleLabel?.font = .pretendard(size: 20, weightName: .bold) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + configureUI() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func updateTapListUI(by type: MyMusicType) { + switch type { + case .drop: + dropTapButton.setTitleColor(.white, for: .normal) + dropTapButton.setTitleColor(.lightGray, for: .highlighted) + dropTapButton.setTitleColor(.white, for: .normal) + dropTapButton.setTitleColor(.lightGray, for: .highlighted) + likeTapButton.setTitleColor(UIColor.gray400, for: .normal) + likeTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + likeTapButton.setTitleColor(UIColor.gray400, for: .normal) + likeTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + + case.like: + dropTapButton.setTitleColor(UIColor.gray400, for: .normal) + dropTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + dropTapButton.setTitleColor(UIColor.gray400, for: .normal) + dropTapButton.setTitleColor(UIColor(hexString: "#43464B"), for: .highlighted) + likeTapButton.setTitleColor(.white, for: .normal) + likeTapButton.setTitleColor(.lightGray, for: .highlighted) + likeTapButton.setTitleColor(.white, for: .normal) + likeTapButton.setTitleColor(.lightGray, for: .highlighted) + } + } +} + +// MARK: - Private Methods + +private extension TapListView { + func configureUI() { + backgroundColor = .gray900 + + addSubview(dropTapButton) + dropTapButton.snp.makeConstraints { + $0.top.bottom.equalToSuperview().inset(10) + $0.leading.equalToSuperview() + $0.width.equalTo(35) + } + + addSubview(likeTapButton) + likeTapButton.snp.makeConstraints { + $0.top.bottom.equalTo(dropTapButton) + $0.leading.equalTo(dropTapButton.snp.trailing).offset(20) + $0.width.equalTo(52) + } + } +} + +// MARK: - TapListView + Rx + +extension Reactive where Base: TapListView { + var onDropTap: Observable { + base.dropTapButton.rx.tap.mapVoid() + .throttle(.seconds(2), scheduler: MainScheduler.instance) + } + + var onLikeTap: Observable { + base.likeTapButton.rx.tap.mapVoid() + .throttle(.seconds(2), scheduler: MainScheduler.instance) + } +} diff --git a/StreetDrop/StreetDrop/Presentation/MyPage/ViewModel/MyPageViewModel.swift b/StreetDrop/StreetDrop/Presentation/MyPage/ViewModel/MyPageViewModel.swift index 382d76b5..f5b8821e 100644 --- a/StreetDrop/StreetDrop/Presentation/MyPage/ViewModel/MyPageViewModel.swift +++ b/StreetDrop/StreetDrop/Presentation/MyPage/ViewModel/MyPageViewModel.swift @@ -12,31 +12,44 @@ import RxRelay import RxSwift final class MyPageViewModel { - private let model = DefaultMyPageModel( - repository: DefaultMyPageRepository( - networkManager: NetworkManager() - ) - ) + private let fetchingMyLevelUseCase: FetchingMyLevelUseCase + private let fetchingLevelPolicyUseCase: FetchingLevelPolicyUseCase + private let fetchingMyDropListUseCase: FetchingMyDropListUseCase + private let fetchingMyLikeListUseCase: FetchingMyLikeListUseCase + private let fetchingSingleMusicUseCase: FetchingSingleMusicUseCase + + private var myMusicType: MyMusicType = .drop - var myDropMusicList: [[MyMusic]] = [] - var myLikeMusicList: [[MyMusic]] = [] + init( + fetchingMyLevelUseCase: FetchingMyLevelUseCase = DefaultFetchingMyLevelUseCase(), + fetchingLevelPolicyUseCase: FetchingLevelPolicyUseCase = DefaultFetchingLevelPolicyUseCase(), + fetchingMyDropListUseCase: FetchingMyDropListUseCase = DefaultFetchingMyDropListUseCase(), + fetchingMyLikeListUseCase: FetchingMyLikeListUseCase = DefaultFetchingMyLikeListUseCase(), + fetchingSingleMusicUseCase: FetchingSingleMusicUseCase = DefaultFetchingSingleMusicUseCase() + ) { + self.fetchingMyLevelUseCase = fetchingMyLevelUseCase + self.fetchingLevelPolicyUseCase = fetchingLevelPolicyUseCase + self.fetchingMyDropListUseCase = fetchingMyDropListUseCase + self.fetchingMyLikeListUseCase = fetchingMyLikeListUseCase + self.fetchingSingleMusicUseCase = fetchingSingleMusicUseCase + } } extension MyPageViewModel: ViewModel { struct Input { - let viewWillAppearEvent: PublishRelay - let levelPolicyTapEvent: PublishRelay - let selectedMusicEvent: PublishRelay + let viewWillAppearEvent: Observable + let listTypeTapEvent: Observable + let levelPolicyTapEvent: Observable + let selectedMusicEvent: Observable + let selectedFilterTypeEvent: Observable } struct Output { let levelImageURL = PublishRelay() let levelName = PublishRelay() let nickName = PublishRelay() - let myDropMusicsSections = PublishRelay<[MyMusicsSection]>() - let myLikeMusicsSections = PublishRelay<[MyMusicsSection]>() - let totalDropMusicsCount = PublishRelay() - let totalLikeMusicsCount = PublishRelay() + let myMusicsSections = PublishRelay<[MyMusicsSectionType]>() + let totalMusicsCount = PublishRelay() let pushCommunityView = PublishRelay() let toast = PublishRelay() let isShowingLevelUpView = PublishRelay() @@ -51,16 +64,46 @@ extension MyPageViewModel: ViewModel { func convert(input: Input, disposedBag: RxSwift.DisposeBag) -> Output { let output = Output() + let lastestListType = PublishRelay() input.viewWillAppearEvent .bind(with: self) { owner, _ in owner.fetchLevelItems(output: output, disposedBag: disposedBag) owner.fetchLevelProgress(output: output, disposeBag: disposedBag) - owner.fetchMyDropMusicsSections(output: output, disposedBag: disposedBag) - owner.fetchMyLikeMusicsSections(output: output, disposedBag: disposedBag) + + lastestListType.accept(owner.myMusicType) } .disposed(by: disposedBag) + input.listTypeTapEvent + .bind(to: lastestListType) + .disposed(by: disposedBag) + + Observable.combineLatest( + lastestListType, + input.selectedFilterTypeEvent + ) + .bind(with: self) { owner, types in + let (myMusicType, selectedFilterType) = types + owner.myMusicType = myMusicType + + switch myMusicType { + case .drop: + owner.fetchMyDropMusicsSections( + filterType: selectedFilterType, + output: output, + disposedBag: disposedBag + ) + case .like: + owner.fetchMyLikeMusicsSections( + filterType: selectedFilterType, + output: output, + disposedBag: disposedBag + ) + } + } + .disposed(by: disposedBag) + input.levelPolicyTapEvent .bind(with: self) { owner, _ in owner.fetchLevelPolicy(output: output, disposeBag: disposedBag) @@ -68,9 +111,9 @@ extension MyPageViewModel: ViewModel { .disposed(by: disposedBag) input.selectedMusicEvent - .bind(with: self) { owner, musicInfo in + .bind(with: self) { owner, itemID in owner.fetchMyDropMusic( - itemID: musicInfo.itemID, + itemID: itemID, output: output, disposedBag: disposedBag ) @@ -81,9 +124,11 @@ extension MyPageViewModel: ViewModel { } } +// MARK: - Private Methods + private extension MyPageViewModel { func fetchLevelItems(output: Output, disposedBag: DisposeBag) { - model.fetchMyLevel() + fetchingMyLevelUseCase.fetchMyLevel() .subscribe { result in switch result { case .success(let levelItem): @@ -98,7 +143,7 @@ private extension MyPageViewModel { } func fetchLevelProgress(output: Output, disposeBag: DisposeBag) { - model.fetchMyLevelProgress() + fetchingMyLevelUseCase.fetchMyLevelProgress() .subscribe(with: self, onSuccess: { owner, progress in output.isShowingLevelUpView.accept(progress.isShow) output.remainCountToLevelUp.accept(progress.remainCount) @@ -112,7 +157,7 @@ private extension MyPageViewModel { } func fetchLevelPolicy(output: Output, disposeBag: DisposeBag) { - model.fetchLevelPolicy() + fetchingLevelPolicyUseCase.fetchLevelPolicy() .subscribe(with: self, onSuccess: { owner, levelPolicies in output.levelPoliciesRelay.accept(levelPolicies) }, onFailure: { _, error in @@ -121,36 +166,36 @@ private extension MyPageViewModel { .disposed(by: disposeBag) } - func fetchMyDropMusicsSections(output: Output, disposedBag: DisposeBag) { - model.fetchMyDropList() + func fetchMyDropMusicsSections( + filterType: FilterType, + output: Output, + disposedBag: DisposeBag + ) { + fetchingMyDropListUseCase.fetchMyDropList(filterType: filterType) .subscribe(with: self, onSuccess: { owner, totalMusics in - output.totalDropMusicsCount.accept(totalMusics.totalCount) - output.myDropMusicsSections.accept( - totalMusics.musics.map { - .init(date: $0.date, items: $0.musics) - } - ) - - owner.myDropMusicList = totalMusics.musics.map { $0.musics } - }, onFailure: { _, _ in - output.myDropMusicsSections.accept([]) + output.totalMusicsCount.accept(totalMusics.totalCount) + let myMusicsSections = owner.convertToSectionTypes(from: totalMusics) + output.myMusicsSections.accept(myMusicsSections) + }, onFailure: { _, error in + print("❌Fetching My Drop List Error: \(error.localizedDescription)") + output.toast.accept("네트워크를 확인해 주세요") }) .disposed(by: disposedBag) } - func fetchMyLikeMusicsSections(output: Output, disposedBag: DisposeBag) { - model.fetchMyLikeList() + func fetchMyLikeMusicsSections( + filterType: FilterType, + output: Output, + disposedBag: DisposeBag + ) { + fetchingMyLikeListUseCase.fetchMyLikeList(filterType: filterType) .subscribe(with: self, onSuccess: { owner, totalMusics in - output.totalLikeMusicsCount.accept(totalMusics.totalCount) - output.myLikeMusicsSections.accept( - totalMusics.musics.map { - .init(date: $0.date, items: $0.musics) - } - ) - - owner.myLikeMusicList = totalMusics.musics.map { $0.musics } - }, onFailure: { _, _ in - output.myLikeMusicsSections.accept([]) + output.totalMusicsCount.accept(totalMusics.totalCount) + let myMusicsSections = owner.convertToSectionTypes(from: totalMusics) + output.myMusicsSections.accept(myMusicsSections) + }, onFailure: { _, error in + print("❌Fetching My Like List Error: \(error.localizedDescription)") + output.toast.accept("네트워크를 확인해 주세요") }) .disposed(by: disposedBag) } @@ -160,7 +205,7 @@ private extension MyPageViewModel { output: Output, disposedBag: DisposeBag ) { - model.fetchMyDropMusic(itemID: itemID) + fetchingSingleMusicUseCase.fetchSingleMusic(itemID: itemID) .subscribe(onSuccess: { musics in if musics.isEmpty == false { output.pushCommunityView.accept(musics) @@ -173,4 +218,13 @@ private extension MyPageViewModel { }) .disposed(by: disposedBag) } + + func convertToSectionTypes(from totalMusics: TotalMyMusics) -> [MyMusicsSectionType] { + return totalMusics.musics.map { myMusics in + MyMusicsSectionType( + section: .musics(date: myMusics.date), + items: myMusics.musics + ) + } + } } diff --git a/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeDetailViewModel.swift b/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeDetailViewModel.swift index c27cc260..95a33268 100644 --- a/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeDetailViewModel.swift +++ b/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeDetailViewModel.swift @@ -14,12 +14,12 @@ protocol NoticeDetailViewModel: ViewModel { } final class DefaultNoticeDetailViewModel: NoticeDetailViewModel { private let noticeId: Int - private let useCase: NoticeUseCase + private let useCase: FetchingNoticeUseCase private let dateManager: DateManager init( noticeId: Int, - useCase: NoticeUseCase = DefaultNoticeUseCase(), + useCase: FetchingNoticeUseCase = DefaultFetchingNoticeUseCase(), dateManager: DateManager = DefaultDateManager() ) { self.noticeId = noticeId diff --git a/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeListViewModel.swift b/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeListViewModel.swift index ffdce005..7697e841 100644 --- a/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeListViewModel.swift +++ b/StreetDrop/StreetDrop/Presentation/Settings/Notice/ViewModel/NoticeListViewModel.swift @@ -13,11 +13,11 @@ import RxSwift protocol NoticeListViewModel: ViewModel { } final class DefaultNoticeListViewModel: NoticeListViewModel { - private let useCase: NoticeUseCase + private let useCase: FetchingNoticeUseCase private let dateManager: DateManager init( - useCase: NoticeUseCase = DefaultNoticeUseCase(), + useCase: FetchingNoticeUseCase = DefaultFetchingNoticeUseCase(), dateManager: DateManager = DefaultDateManager() ) { self.useCase = useCase diff --git a/StreetDrop/StreetDrop/Presentation/Utils/Extension/UIcolor+.swift b/StreetDrop/StreetDrop/Presentation/Utils/Extension/UIcolor+.swift index 444a7f3c..e140ee40 100644 --- a/StreetDrop/StreetDrop/Presentation/Utils/Extension/UIcolor+.swift +++ b/StreetDrop/StreetDrop/Presentation/Utils/Extension/UIcolor+.swift @@ -215,4 +215,8 @@ public extension UIColor { static var systemCritical: UIColor { UIColor(hexString: "#F47068") } + + static var main_100: UIColor { + UIColor(hexString: "#88F6FC") + } } diff --git a/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift b/StreetDrop/StreetDrop/Presentation/Utils/OptionModalViewController.swift index 43860cef..da5a9f19 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() @@ -76,7 +85,7 @@ final class OptionModalViewController: UIViewController { //나타날때 모달 뒤 화면 뿌옇게 UIView.animate(withDuration: 0.4) { - self.dimmedView.alpha = 0.25 + self.dimmedView.alpha = 0.5 } } } @@ -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-arrow-down.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-arrow-down.imageset/Contents.json new file mode 100644 index 00000000..55f0264c --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-arrow-down.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-arrow-down.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-arrow-down.imageset/icon-arrow-down.svg b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-arrow-down.imageset/icon-arrow-down.svg new file mode 100644 index 00000000..abdf33ef --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-arrow-down.imageset/icon-arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/Contents.json new file mode 100644 index 00000000..9c0394e1 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-check.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/icon-check.svg b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/icon-check.svg new file mode 100644 index 00000000..bf76bdc0 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-check.imageset/icon-check.svg @@ -0,0 +1,3 @@ + + + diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/Contents.json new file mode 100644 index 00000000..91a70053 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-filter.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/icon-filter.svg b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/icon-filter.svg new file mode 100644 index 00000000..3d41d934 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-filter.imageset/icon-filter.svg @@ -0,0 +1,4 @@ + + + + diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/Contents.json new file mode 100644 index 00000000..7c5f59fa --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-heart-empty.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/icon-heart-empty.svg b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/icon-heart-empty.svg new file mode 100644 index 00000000..a3129e83 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-empty.imageset/icon-heart-empty.svg @@ -0,0 +1,3 @@ + + + diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/Contents.json b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/Contents.json new file mode 100644 index 00000000..ab1fb1a5 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon-heart-fill.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/icon-heart-fill.svg b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/icon-heart-fill.svg new file mode 100644 index 00000000..6b328027 --- /dev/null +++ b/StreetDrop/StreetDrop/Resource/Assets.xcassets/icon-heart-fill.imageset/icon-heart-fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/StreetDrop/StreetDrop/Util/Extensions/Date+TimeAgoDisplay.swift b/StreetDrop/StreetDrop/Util/Extensions/Date+TimeAgoDisplay.swift new file mode 100644 index 00000000..6566a3aa --- /dev/null +++ b/StreetDrop/StreetDrop/Util/Extensions/Date+TimeAgoDisplay.swift @@ -0,0 +1,46 @@ +// +// Date+TimeAgoDisplay.swift +// StreetDrop +// +// Created by thoonk on 9/30/24. +// + +import Foundation + +extension Date { + func timeAgoDisplay(from date: Date) -> String { + let calendar = Calendar.current + let components = calendar.dateComponents([ + .year, + .month, + .weekOfYear, + .day, + .hour, + .minute, + .second + ], from: date, to: self) + + if let years = components.year, years > 0 { + return "\(years)년 전" + } + if let months = components.month, months > 0 { + return "\(months)달 전" + } + if let weeks = components.weekOfYear, weeks > 0 { + return "\(weeks)주 전" + } + if let days = components.day, days > 0 { + return "\(days)일 전" + } + if let hours = components.hour, hours > 0 { + return "\(hours)시간 전" + } + if let minutes = components.minute, minutes > 0 { + return "\(minutes)분 전" + } + if let seconds = components.second, seconds > 0 { + return "\(seconds)초 전" + } + return "1초 전" + } +} diff --git a/StreetDrop/StreetDrop/Util/Extensions/Map+Rx.swift b/StreetDrop/StreetDrop/Util/Extensions/Map+Rx.swift new file mode 100644 index 00000000..91c1fe87 --- /dev/null +++ b/StreetDrop/StreetDrop/Util/Extensions/Map+Rx.swift @@ -0,0 +1,20 @@ +// +// Map+Rx.swift +// StreetDrop +// +// Created by thoonk on 7/10/24. +// + +import Foundation + +import RxSwift + +extension ObservableType { + func map(_ element: T) -> Observable { + self.map({ _ in element }) + } + + func mapVoid() -> Observable { + self.map(Void()) + } +} diff --git a/StreetDrop/StreetDrop/Util/Extensions/String+ToDate.swift b/StreetDrop/StreetDrop/Util/Extensions/String+ToDate.swift new file mode 100644 index 00000000..07eeba6e --- /dev/null +++ b/StreetDrop/StreetDrop/Util/Extensions/String+ToDate.swift @@ -0,0 +1,20 @@ +// +// String+ToDate.swift +// StreetDrop +// +// Created by thoonk on 9/30/24. +// + +import Foundation + +extension String { + func toDate( + format: String = "yyyy-MM-dd HH:mm:ss", + timeZone: TimeZone? = TimeZone(identifier: "Asia/Seoul") + ) -> Date? { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + dateFormatter.timeZone = timeZone + return dateFormatter.date(from: self) + } +} diff --git a/StreetDrop/StreetDrop/Util/Extensions/UIViewController+Rx.swift b/StreetDrop/StreetDrop/Util/Extensions/UIViewController+Rx.swift new file mode 100644 index 00000000..cfc7866d --- /dev/null +++ b/StreetDrop/StreetDrop/Util/Extensions/UIViewController+Rx.swift @@ -0,0 +1,73 @@ +// +// UIViewController+Rx.swift +// StreetDrop +// +// Created by thoonk on 7/10/24. +// + +import Foundation +import UIKit + +import RxSwift +import RxCocoa + +extension Reactive where Base: UIViewController { + var viewDidLoad: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in } + return ControlEvent(events: source) + } + + var viewWillAppear: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewWillAppear)).map { $0.first as? Bool ?? false } + return ControlEvent(events: source) + } + var viewDidAppear: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewDidAppear)).map { $0.first as? Bool ?? false } + return ControlEvent(events: source) + } + + var viewWillDisappear: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewWillDisappear)).map { $0.first as? Bool ?? false } + return ControlEvent(events: source) + } + var viewDidDisappear: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewDidDisappear)).map { $0.first as? Bool ?? false } + return ControlEvent(events: source) + } + + var viewWillLayoutSubviews: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewWillLayoutSubviews)).map { _ in } + return ControlEvent(events: source) + } + var viewDidLayoutSubviews: ControlEvent { + let source = self.methodInvoked(#selector(Base.viewDidLayoutSubviews)).map { _ in } + return ControlEvent(events: source) + } + + var willMoveToParentViewController: ControlEvent { + let source = self.methodInvoked(#selector(Base.willMove)).map { $0.first as? UIViewController } + return ControlEvent(events: source) + } + var didMoveToParentViewController: ControlEvent { + let source = self.methodInvoked(#selector(Base.didMove)).map { $0.first as? UIViewController } + return ControlEvent(events: source) + } + + var didReceiveMemoryWarning: ControlEvent { + let source = self.methodInvoked(#selector(Base.didReceiveMemoryWarning)).map { _ in } + return ControlEvent(events: source) + } + + /// Rx observable, triggered when the ViewController appearance state changes (true if the View is being displayed, false otherwise) + var isVisible: Observable { + let viewDidAppearObservable = self.base.rx.viewDidAppear.map { _ in true } + let viewWillDisappearObservable = self.base.rx.viewWillDisappear.map { _ in false } + return Observable.merge(viewDidAppearObservable, viewWillDisappearObservable) + } + + /// Rx observable, triggered when the ViewController is being dismissed + var isDismissing: ControlEvent { + let source = self.sentMessage(#selector(Base.dismiss)).map { $0.first as? Bool ?? false } + return ControlEvent(events: source) + } +}