diff --git a/FindTown/FindTown.xcodeproj/project.pbxproj b/FindTown/FindTown.xcodeproj/project.pbxproj index 13b1c980..cace878f 100644 --- a/FindTown/FindTown.xcodeproj/project.pbxproj +++ b/FindTown/FindTown.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2B1CC56E2B2F1EC4003C846C /* EmptyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B1CC56D2B2F1EC4003C846C /* EmptyType.swift */; }; 2B1E63252AFB68CE00D35A05 /* SearchType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B1E63242AFB68CE00D35A05 /* SearchType.swift */; }; 2B3266252A4D77FA00F883B0 /* APIKeyInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2B3266242A4D77FA00F883B0 /* APIKeyInfo.plist */; }; 2B42E970299F83DB0093FB0A /* UserDefaultsWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B42E96F299F83DB0093FB0A /* UserDefaultsWrapper.swift */; }; @@ -42,8 +43,18 @@ 2B628DF82987853300A90D9A /* TownRank.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B628DF72987853300A90D9A /* TownRank.swift */; }; 2B718C182966A5930068884A /* MapCategoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B718C172966A5930068884A /* MapCategoryCollectionViewCell.swift */; }; 2B718C1A2966A6000068884A /* MapCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B718C192966A6000068884A /* MapCategory.swift */; }; + 2B74F61A2AFB78A2002A6A5F /* PlaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F6192AFB78A2002A6A5F /* PlaceViewController.swift */; }; + 2B74F61C2AFB78B3002A6A5F /* PlaceCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F61B2AFB78B3002A6A5F /* PlaceCoordinator.swift */; }; + 2B74F6202AFB7C3E002A6A5F /* PlaceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F61F2AFB7C3E002A6A5F /* PlaceViewModel.swift */; }; + 2B74F6232AFB7F4B002A6A5F /* BannerCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F6222AFB7F4B002A6A5F /* BannerCollectionView.swift */; }; + 2B74F6252AFB7F66002A6A5F /* BannerCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F6242AFB7F66002A6A5F /* BannerCollectionViewCell.swift */; }; + 2B74F6282AFB7FCE002A6A5F /* BannerCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74F6272AFB7FCE002A6A5F /* BannerCollectionViewFlowLayout.swift */; }; 2B7AE8312987F59200DF19C8 /* TownIntroCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B7AE8302987F59200DF19C8 /* TownIntroCoordinator.swift */; }; + 2B83027D2B1632440029D4A4 /* ThemeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B83027C2B1632440029D4A4 /* ThemeCollectionViewCell.swift */; }; + 2B8302822B1C45460029D4A4 /* PlaceTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B8302812B1C45460029D4A4 /* PlaceTableView.swift */; }; + 2B8302842B1C45680029D4A4 /* PlaceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B8302832B1C45680029D4A4 /* PlaceTableViewCell.swift */; }; 2BA009B129A2248300F3563A /* TownIntroduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA009B029A2248300F3563A /* TownIntroduce.swift */; }; + 2BBC53652B13A54F008FB237 /* ThemeCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BBC53642B13A54F008FB237 /* ThemeCollectionViewFlowLayout.swift */; }; 2BE478172AEFF98900DF8632 /* NMapsMap in Frameworks */ = {isa = PBXBuildFile; productRef = 2BE478162AEFF98900DF8632 /* NMapsMap */; }; 2BED7FA82AF6057800EFBFD6 /* SearchedDongCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BED7FA72AF6057700EFBFD6 /* SearchedDongCollectionView.swift */; }; 2BED7FAA2AF6058600EFBFD6 /* SearchedDongCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BED7FA92AF6058600EFBFD6 /* SearchedDongCollectionViewCell.swift */; }; @@ -256,6 +267,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 2B1CC56D2B2F1EC4003C846C /* EmptyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyType.swift; sourceTree = ""; }; 2B1E63242AFB68CE00D35A05 /* SearchType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchType.swift; sourceTree = ""; }; 2B3266242A4D77FA00F883B0 /* APIKeyInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = APIKeyInfo.plist; path = ../../../../../APIKeyInfo.plist; sourceTree = ""; }; 2B42E96F299F83DB0093FB0A /* UserDefaultsWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsWrapper.swift; sourceTree = ""; }; @@ -290,8 +302,18 @@ 2B628DF72987853300A90D9A /* TownRank.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TownRank.swift; sourceTree = ""; }; 2B718C172966A5930068884A /* MapCategoryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCategoryCollectionViewCell.swift; sourceTree = ""; }; 2B718C192966A6000068884A /* MapCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCategory.swift; sourceTree = ""; }; + 2B74F6192AFB78A2002A6A5F /* PlaceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceViewController.swift; sourceTree = ""; }; + 2B74F61B2AFB78B3002A6A5F /* PlaceCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceCoordinator.swift; sourceTree = ""; }; + 2B74F61F2AFB7C3E002A6A5F /* PlaceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceViewModel.swift; sourceTree = ""; }; + 2B74F6222AFB7F4B002A6A5F /* BannerCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerCollectionView.swift; sourceTree = ""; }; + 2B74F6242AFB7F66002A6A5F /* BannerCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerCollectionViewCell.swift; sourceTree = ""; }; + 2B74F6272AFB7FCE002A6A5F /* BannerCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerCollectionViewFlowLayout.swift; sourceTree = ""; }; 2B7AE8302987F59200DF19C8 /* TownIntroCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TownIntroCoordinator.swift; sourceTree = ""; }; + 2B83027C2B1632440029D4A4 /* ThemeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeCollectionViewCell.swift; sourceTree = ""; }; + 2B8302812B1C45460029D4A4 /* PlaceTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceTableView.swift; sourceTree = ""; }; + 2B8302832B1C45680029D4A4 /* PlaceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceTableViewCell.swift; sourceTree = ""; }; 2BA009B029A2248300F3563A /* TownIntroduce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TownIntroduce.swift; sourceTree = ""; }; + 2BBC53642B13A54F008FB237 /* ThemeCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeCollectionViewFlowLayout.swift; sourceTree = ""; }; 2BED7FA72AF6057700EFBFD6 /* SearchedDongCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchedDongCollectionView.swift; sourceTree = ""; }; 2BED7FA92AF6058600EFBFD6 /* SearchedDongCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchedDongCollectionViewCell.swift; sourceTree = ""; }; 2BED7FAC2AF6090300EFBFD6 /* SearchedDongCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchedDongCollectionViewFlowLayout.swift; sourceTree = ""; }; @@ -636,6 +658,53 @@ path = TownIntroScene; sourceTree = ""; }; + 2B74F6182AFB788C002A6A5F /* PlaceScene */ = { + isa = PBXGroup; + children = ( + 2B74F61D2AFB79F9002A6A5F /* Flows */, + 2B74F61E2AFB7A01002A6A5F /* Place */, + ); + path = PlaceScene; + sourceTree = ""; + }; + 2B74F61D2AFB79F9002A6A5F /* Flows */ = { + isa = PBXGroup; + children = ( + 2B74F61B2AFB78B3002A6A5F /* PlaceCoordinator.swift */, + ); + path = Flows; + sourceTree = ""; + }; + 2B74F61E2AFB7A01002A6A5F /* Place */ = { + isa = PBXGroup; + children = ( + 2B74F6212AFB7F31002A6A5F /* SubViews */, + 2B74F6192AFB78A2002A6A5F /* PlaceViewController.swift */, + 2B74F61F2AFB7C3E002A6A5F /* PlaceViewModel.swift */, + ); + path = Place; + sourceTree = ""; + }; + 2B74F6212AFB7F31002A6A5F /* SubViews */ = { + isa = PBXGroup; + children = ( + 2B83027E2B1C44C10029D4A4 /* PlaceTableView */, + 2B8302792B1631A80029D4A4 /* ThemeCollectionView */, + 2B74F6262AFB7F6F002A6A5F /* BannerCollectionView */, + ); + path = SubViews; + sourceTree = ""; + }; + 2B74F6262AFB7F6F002A6A5F /* BannerCollectionView */ = { + isa = PBXGroup; + children = ( + 2B74F6222AFB7F4B002A6A5F /* BannerCollectionView.swift */, + 2B74F6242AFB7F66002A6A5F /* BannerCollectionViewCell.swift */, + 2B74F6272AFB7FCE002A6A5F /* BannerCollectionViewFlowLayout.swift */, + ); + path = BannerCollectionView; + sourceTree = ""; + }; 2B7AE82F2987F55D00DF19C8 /* Flows */ = { isa = PBXGroup; children = ( @@ -644,6 +713,24 @@ path = Flows; sourceTree = ""; }; + 2B8302792B1631A80029D4A4 /* ThemeCollectionView */ = { + isa = PBXGroup; + children = ( + 2BBC53642B13A54F008FB237 /* ThemeCollectionViewFlowLayout.swift */, + 2B83027C2B1632440029D4A4 /* ThemeCollectionViewCell.swift */, + ); + path = ThemeCollectionView; + sourceTree = ""; + }; + 2B83027E2B1C44C10029D4A4 /* PlaceTableView */ = { + isa = PBXGroup; + children = ( + 2B8302812B1C45460029D4A4 /* PlaceTableView.swift */, + 2B8302832B1C45680029D4A4 /* PlaceTableViewCell.swift */, + ); + path = PlaceTableView; + sourceTree = ""; + }; 2BED7FAB2AF608D800EFBFD6 /* SearchedDongCollectionView */ = { isa = PBXGroup; children = ( @@ -858,6 +945,7 @@ BC6EFB75293B9C3800AB3332 /* Presentation */ = { isa = PBXGroup; children = ( + 2B74F6182AFB788C002A6A5F /* PlaceScene */, BC32F825299D48B00038F0D6 /* SearchScene */, BCF8258E2988C8D900AC00BB /* MyPageScene */, 2B628DF62987803100A90D9A /* TownIntroScene */, @@ -1324,6 +1412,7 @@ 2B42E98B29A0688D0093FB0A /* Traffic.swift */, F3918469299BCE9200CEF02E /* MapTransition.swift */, F32F849D29A49F9200EA403C /* InfraSubCategory.swift */, + 2B1CC56D2B2F1EC4003C846C /* EmptyType.swift */, ); path = Enumerations; sourceTree = ""; @@ -1669,6 +1758,7 @@ BCF825922988C90C00AC00BB /* MyPageViewController.swift in Sources */, BC04A6DC296FDEC100B60BCF /* KeyChainManager.swift in Sources */, 2BED7FAF2AF60FB200EFBFD6 /* Search.swift in Sources */, + 2B1CC56E2B2F1EC4003C846C /* EmptyType.swift in Sources */, 2B7AE8312987F59200DF19C8 /* TownIntroCoordinator.swift in Sources */, F38CCBD729582869000C16AF /* AppCoordinator.swift in Sources */, 2B628DD7298650CD00A90D9A /* TownIntroduceViewModel.swift in Sources */, @@ -1697,6 +1787,7 @@ BC853DED298B80DD0033AF20 /* DefaultMemberUseCase.swift in Sources */, F38CCBEA29582881000C16AF /* MapCoordinator.swift in Sources */, BC1CE298297545D600F89B81 /* TrafficCollectionViewCell.swift in Sources */, + 2B74F61A2AFB78A2002A6A5F /* PlaceViewController.swift in Sources */, BC32F829299D48FC0038F0D6 /* SearchCoordinator.swift in Sources */, BC8B638F298A4B5B004E1116 /* ChangeNicknameViewController.swift in Sources */, F39EDDC2296D635100A4E655 /* CityType.swift in Sources */, @@ -1716,6 +1807,7 @@ BC0D88552963DD1D00CCB800 /* KakaoAddressViewController.swift in Sources */, F3356F00298F986A002B9FFD /* TokenPayloadDTO.swift in Sources */, F3356EEA298D4D59002B9FFD /* ReissueRequest.swift in Sources */, + 2B74F6252AFB7F66002A6A5F /* BannerCollectionViewCell.swift in Sources */, 2B4A59BB2AF22739009012D1 /* PlaceInfoView.swift in Sources */, F38AA7FE2981259200EF66F2 /* DefaultAuthUseCase.swift in Sources */, BC056C5C2962B2C400EDCA18 /* LoginViewController.swift in Sources */, @@ -1725,6 +1817,7 @@ F362189D29B99AE2005A0C8F /* TokenRepository.swift in Sources */, 2BED7FAA2AF6058600EFBFD6 /* SearchedDongCollectionViewCell.swift in Sources */, BC3C069229A0C5A20049DA8C /* TownSearchRequest.swift in Sources */, + 2B83027D2B1632440029D4A4 /* ThemeCollectionViewCell.swift in Sources */, BCE996662976915A00AACD02 /* FilterCollectionViewFlowLayout.swift in Sources */, 2B628DD52986508F00A90D9A /* TownIntroduceViewController.swift in Sources */, 2BA009B129A2248300F3563A /* TownIntroduce.swift in Sources */, @@ -1750,7 +1843,9 @@ F3984A7429ACBE03003FA0C8 /* AppDIContainer.swift in Sources */, BC8B638D298A4B4C004E1116 /* ChangeNicknameViewModel.swift in Sources */, BC9F4D59296BE5FC0099473C /* FavoriteTownViewController.swift in Sources */, + 2B8302842B1C45680029D4A4 /* PlaceTableViewCell.swift in Sources */, F3918476299E8B9700CEF02E /* MapThemaStoreResponseDTO.swift in Sources */, + 2BBC53652B13A54F008FB237 /* ThemeCollectionViewFlowLayout.swift in Sources */, F3918461299A693400CEF02E /* ThemaStore.swift in Sources */, BC853E00298C04D00033AF20 /* MyPageAnonymousViewModel.swift in Sources */, BC7BCBCF29646EEA003BB4FF /* TownMoodViewModel.swift in Sources */, @@ -1759,6 +1854,7 @@ BC7508E82975284800D0CAFA /* FilterBottomSheetViewModel.swift in Sources */, BC9F4D60296BF0D30099473C /* AgreePolicyViewModel.swift in Sources */, 2B557B0D29A279B400232DAE /* FavoriteResponseDTO.swift in Sources */, + 2B74F6232AFB7F4B002A6A5F /* BannerCollectionView.swift in Sources */, F363D167299A39D200606C7F /* MapConstant.swift in Sources */, 2B1E63252AFB68CE00D35A05 /* SearchType.swift in Sources */, BC056C5A2962B2B900EDCA18 /* LoginViewModel.swift in Sources */, @@ -1782,6 +1878,7 @@ BC8B638729894EE1004E1116 /* MyPageCollectionView.swift in Sources */, BCB554B32977AEA8007E1BBA /* VillageYearMonth.swift in Sources */, BC199C42297FE96E00C2A89B /* ShowVillageListViewModel.swift in Sources */, + 2B74F6202AFB7C3E002A6A5F /* PlaceViewModel.swift in Sources */, BC9E86522966821C00AB4AE7 /* SignupViewModelDelegate.swift in Sources */, F38CCBE829582881000C16AF /* MapViewController.swift in Sources */, F3356EFA298EB918002B9FFD /* LoginConfirmRequest.swift in Sources */, @@ -1802,6 +1899,7 @@ F3219B7A2969D53D000024E4 /* AddressSheetCoordinator.swift in Sources */, F33454D029A611A20075E66B /* TokenData.swift in Sources */, BCF68B5A299BB2B900E8D83E /* TownFilterResponseDTO.swift in Sources */, + 2B74F6282AFB7FCE002A6A5F /* BannerCollectionViewFlowLayout.swift in Sources */, 2B718C1A2966A6000068884A /* MapCategory.swift in Sources */, F38CCBE12958287C000C16AF /* HomeCoordinator.swift in Sources */, 2BEE90C52977F90A002E7C3A /* FavoriteViewController.swift in Sources */, @@ -1819,6 +1917,7 @@ F38AA82B29842C2D00EF66F2 /* SigninUserModel.swift in Sources */, F3984AA529ADAD45003FA0C8 /* AppleAuthRespository.swift in Sources */, F38AA7F429811F0600EF66F2 /* DefaultKakaoAuthRepository.swift in Sources */, + 2B74F61C2AFB78B3002A6A5F /* PlaceCoordinator.swift in Sources */, F3918472299D3F0600CEF02E /* ResignRequest.swift in Sources */, F3356F02298FA270002B9FFD /* LogoutRequest.swift in Sources */, BCF825992988DFF800AC00BB /* SupportSectionCollectionViewCell.swift in Sources */, @@ -1856,6 +1955,7 @@ F3219B742969B351000024E4 /* StoreDetailType.swift in Sources */, BC354708298F9D010016FE4A /* ServiceMapPopUpViewController.swift in Sources */, BCF68B56299BB25C00E8D83E /* TownFilterRequest.swift in Sources */, + 2B8302822B1C45460029D4A4 /* PlaceTableView.swift in Sources */, BC1CE29429753F9E00F89B81 /* InfraIconStackView.swift in Sources */, F36218A129B99AE2005A0C8F /* AuthRepository.swift in Sources */, 2B628DF529869F0C00A90D9A /* TownRankView.swift in Sources */, diff --git a/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..4d59385f --- /dev/null +++ b/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcschemes/xcschememanagement.plist b/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcschemes/xcschememanagement.plist index 1d22d696..26f99abb 100644 --- a/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/FindTown/FindTown.xcodeproj/xcuserdata/jsy.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ FindTown.xcscheme_^#shared#^_ orderHint - 1 + 0 Rx (Playground) 1.xcscheme @@ -30,6 +30,27 @@ orderHint 4 + SnapKitPlayground (Playground) 1.xcscheme + + isShown + + orderHint + 5 + + SnapKitPlayground (Playground) 2.xcscheme + + isShown + + orderHint + 6 + + SnapKitPlayground (Playground).xcscheme + + isShown + + orderHint + 4 + diff --git a/FindTown/FindTown/Domain/Enumerations/EmptyType.swift b/FindTown/FindTown/Domain/Enumerations/EmptyType.swift new file mode 100644 index 00000000..788174c4 --- /dev/null +++ b/FindTown/FindTown/Domain/Enumerations/EmptyType.swift @@ -0,0 +1,49 @@ +// +// EmptyType.swift +// FindTown +// +// Created by 장선영 on 2023/12/17. +// + +import Foundation + +enum EmptyType { + case emptyFavorite + case emptyPlace + + var title: String { + switch self { + case .emptyFavorite: + return "찜한 동네가 아직 없어요." + case .emptyPlace: + return "아직 제보된 장소가 없어요." + } + } + + var subTitle: String { + switch self { + case .emptyFavorite: + return "나에게 맞는 동네를 찾아서 찜해보세요!" + case .emptyPlace: + return "우리 동네에서 추천할만한 장소가 있다면 \n알려주세요!" + } + } + + var iconImage: UIImage { + switch self { + case .emptyFavorite: + return UIImage(named: "emptyIcon") ?? UIImage() + case .emptyPlace: + return UIImage(named: "ic_no place") ?? UIImage() + } + } + + var isButtonHidden: Bool { + switch self { + case .emptyFavorite: + return false + case .emptyPlace: + return true + } + } +} diff --git a/FindTown/FindTown/Domain/Enumerations/ThemaCategory.swift b/FindTown/FindTown/Domain/Enumerations/ThemaCategory.swift index be90c465..e3586b8e 100644 --- a/FindTown/FindTown/Domain/Enumerations/ThemaCategory.swift +++ b/FindTown/FindTown/Domain/Enumerations/ThemaCategory.swift @@ -8,6 +8,7 @@ import UIKit enum ThemaCategory: CaseIterable, Category { + case every case restaurantForEatingAlone case cafeForStudy @@ -17,6 +18,8 @@ enum ThemaCategory: CaseIterable, Category { return "혼밥하기 좋은 식당" case .cafeForStudy: return "카공하기 좋은 카페" + case .every: + return "전체" } } @@ -26,6 +29,8 @@ enum ThemaCategory: CaseIterable, Category { return UIImage(named: "thema.restaurant") case .cafeForStudy: return UIImage(named: "thema.notebook") + case .every: + return nil } } @@ -35,6 +40,8 @@ enum ThemaCategory: CaseIterable, Category { return "001" case .restaurantForEatingAlone: return "002" + case .every: + return "" } } } diff --git a/FindTown/FindTown/Presentation/Common/Flow/TabBarCoordinator.swift b/FindTown/FindTown/Presentation/Common/Flow/TabBarCoordinator.swift index 10a9e4e8..5906886f 100644 --- a/FindTown/FindTown/Presentation/Common/Flow/TabBarCoordinator.swift +++ b/FindTown/FindTown/Presentation/Common/Flow/TabBarCoordinator.swift @@ -29,8 +29,13 @@ final class TabBarCoordinator: FlowCoordinator { let homeCoordinator = HomeCoordinator(presentationStyle: .none, appDIContainer: appDIContainer) homeCoordinator.start() - guard let homeViewController = homeCoordinator.navigationController else { return UIViewController() } - homeViewController.tabBarItem = UITabBarItem(title: "동네 찾기", image: UIImage(named: "homeIcon"), tag: 0) + guard let homeViewController = homeCoordinator.navigationController else { + return UIViewController() + } + homeViewController.tabBarItem = UITabBarItem( + title: "동네 찾기", + image: UIImage(named: "homeIcon"), + tag: 0) /// 지도 탭 let mapCoordinator = MapCoordinator(presentationStyle: .none, @@ -38,15 +43,36 @@ final class TabBarCoordinator: FlowCoordinator { mapTransition: .tapBar, appDIContainer: appDIContainer) mapCoordinator.start() - guard let mapViewController = mapCoordinator.navigationController else { return UIViewController() } - mapViewController.tabBarItem = UITabBarItem(title: "동네 지도", image: UIImage(named: "mapIcon"), tag: 1) + guard let mapViewController = mapCoordinator.navigationController else { + return UIViewController() + } + mapViewController.tabBarItem = UITabBarItem( + title: "동네 지도", + image: UIImage(named: "mapIcon"), + tag: 1) + + /// 플레이스 탭 + let placeCoordinator = PlaceCoordinator(presentationStyle: .none, + appDIContainer: appDIContainer) + placeCoordinator.start() + guard let placeViewController = placeCoordinator.navigationController else { + return UIViewController() + } + placeViewController.tabBarItem = UITabBarItem( + title: "플레이스", + image: UIImage(named: "placeIcon"), + tag: 2) /// 찜 탭 let favoriteCoordinator = FavoriteCoordinator(presentationStyle: .none, appDIContainer: appDIContainer) favoriteCoordinator.start() - guard let favoriteViewController = favoriteCoordinator.navigationController else { return UIViewController() } - favoriteViewController.tabBarItem = UITabBarItem(title: "찜", image: UIImage(named: "favoriteIcon"), tag: 2) + guard let favoriteViewController = favoriteCoordinator.navigationController else { return UIViewController() + } + favoriteViewController.tabBarItem = UITabBarItem( + title: "찜", + image: UIImage(named: "favoriteIcon"), + tag: 2) let homeVC = homeViewController.viewControllers.first as? HomeViewController if let favoriteVC = favoriteViewController.viewControllers.first as? FavoriteViewController { @@ -57,12 +83,17 @@ final class TabBarCoordinator: FlowCoordinator { let myPageCoordinator = MyPageCoordinator(presentationStyle: .none, appDIContainer: appDIContainer) myPageCoordinator.start() - guard let myPageViewController = myPageCoordinator.navigationController else { return UIViewController() } - myPageViewController.tabBarItem = UITabBarItem(title: "마이", image: UIImage(named: "myPageIcon"), tag: 3) + guard let myPageViewController = myPageCoordinator.navigationController else { + return UIViewController() } + myPageViewController.tabBarItem = UITabBarItem( + title: "마이", + image: UIImage(named: "myPageIcon"), + tag: 3) /// 탭 바 tabBarController.viewControllers = [homeViewController, mapViewController, + placeViewController, favoriteViewController, myPageViewController] diff --git a/FindTown/FindTown/Presentation/FavoriteScene/Favorite/FavoriteViewController.swift b/FindTown/FindTown/Presentation/FavoriteScene/Favorite/FavoriteViewController.swift index fc5c48ee..f4bb3a37 100644 --- a/FindTown/FindTown/Presentation/FavoriteScene/Favorite/FavoriteViewController.swift +++ b/FindTown/FindTown/Presentation/FavoriteScene/Favorite/FavoriteViewController.swift @@ -25,7 +25,7 @@ final class FavoriteViewController: BaseViewController { // MARK: - Views fileprivate let anonymousView = AnonymousView() - fileprivate let isEmptyView = EmptyView() + fileprivate let isEmptyView = EmptyView(type: .emptyFavorite) fileprivate let favoriteTableView = FavoriteTableView() fileprivate let refreshControl = UIRefreshControl() diff --git a/FindTown/FindTown/Presentation/FavoriteScene/Favorite/SubViews/EmptyView.swift b/FindTown/FindTown/Presentation/FavoriteScene/Favorite/SubViews/EmptyView.swift index 64ee179d..c8a9d0de 100644 --- a/FindTown/FindTown/Presentation/FavoriteScene/Favorite/SubViews/EmptyView.swift +++ b/FindTown/FindTown/Presentation/FavoriteScene/Favorite/SubViews/EmptyView.swift @@ -12,18 +12,21 @@ import FindTownUI final class EmptyView: UIView { private let iconImageView = UIImageView() - private let titleLabel = FindTownLabel(text: "찜한 동네가 아직 없어요.", + private lazy var titleLabel = FindTownLabel(text: type.title, font: .body1, textColor: .grey6, textAlignment: .center) - private let subLabel = FindTownLabel(text: "나에게 맞는 동네를 찾아서 찜해보세요!", + private lazy var subLabel = FindTownLabel(text: type.subTitle, font: .body4, textColor: .grey5, textAlignment: .center) let findOutButton = FTButton(style: .mediumFilled) - override init(frame: CGRect) { - super.init(frame: frame) + let type: EmptyType + + init(type: EmptyType) { + self.type = type + super.init(frame: .zero) setupLayout() setupView() } @@ -67,9 +70,11 @@ private extension EmptyView { func setupView() { self.backgroundColor = .clear - iconImageView.image = UIImage(named: "emptyIcon") + iconImageView.image = type.iconImage titleLabel.setLineHeight(lineHeight: 24.0) subLabel.setLineHeight(lineHeight: 20.0) + subLabel.numberOfLines = 2 findOutButton.setTitle("나에게 맞는 동네 찾기", for: .normal) + findOutButton.isHidden = type.isButtonHidden } } diff --git a/FindTown/FindTown/Presentation/MapScene/Map/MapViewController.swift b/FindTown/FindTown/Presentation/MapScene/Map/MapViewController.swift index bd299c86..6a4dff99 100644 --- a/FindTown/FindTown/Presentation/MapScene/Map/MapViewController.swift +++ b/FindTown/FindTown/Presentation/MapScene/Map/MapViewController.swift @@ -41,7 +41,7 @@ final class MapViewController: BaseViewController { }() private let mapToggle = MapSegmentControl(items: ["인프라", "테마"]) fileprivate let detailCategoryView = MapDetailCategoryView() - private let categoryCollectionView = CategoryCollectionView() + private let categoryCollectionView = CategoryCollectionView(type: .map) fileprivate let storeCollectionView = StoreCollectionView() private let moveToIntroduceButton: FTButton = { let button = FTButton(style: .round) @@ -249,7 +249,8 @@ final class MapViewController: BaseViewController { if index == 0 { self?.viewModel?.output.categoryDataSource.onNext(InfraCategory.allCases) } else { - self?.viewModel?.output.categoryDataSource.onNext(ThemaCategory.allCases) + self?.viewModel?.output.categoryDataSource + .onNext(ThemaCategory.allCases.filter { $0 != .every }) } } .disposed(by: disposeBag) @@ -316,6 +317,10 @@ final class MapViewController: BaseViewController { self.storeCollectionView.delegate = self self.emptyDataInformLabel.isHidden = true + categoryCollectionView.register( + MapCategoryCollectionViewCell.self, + forCellWithReuseIdentifier: MapCategoryCollectionViewCell.reuseIdentifier + ) setMapZoomLevel() setMapLayerGrounp() } @@ -343,13 +348,19 @@ private extension MapViewController { ]) NSLayoutConstraint.activate([ - addressButton.leadingAnchor.constraint(equalTo: naviBarSubView.leadingAnchor, constant: 16.0), - addressButton.bottomAnchor.constraint(equalTo: naviBarSubView.bottomAnchor, constant: -8.0) + addressButton.leadingAnchor.constraint( + equalTo: naviBarSubView.leadingAnchor, + constant: 16.0), + addressButton.topAnchor.constraint( + equalTo: naviBarSubView.topAnchor, + constant: 24.0) ]) NSLayoutConstraint.activate([ mapToggle.centerYAnchor.constraint(equalTo: naviBarSubView.centerYAnchor), - mapToggle.trailingAnchor.constraint(equalTo: naviBarSubView.trailingAnchor, constant: -16.0) + mapToggle.trailingAnchor.constraint( + equalTo: naviBarSubView.trailingAnchor, + constant: -16.0) ]) } diff --git a/FindTown/FindTown/Presentation/MapScene/Map/SubViews/CategoryCollectionView.swift b/FindTown/FindTown/Presentation/MapScene/Map/SubViews/CategoryCollectionView.swift index 01058821..3e944323 100644 --- a/FindTown/FindTown/Presentation/MapScene/Map/SubViews/CategoryCollectionView.swift +++ b/FindTown/FindTown/Presentation/MapScene/Map/SubViews/CategoryCollectionView.swift @@ -7,10 +7,19 @@ import UIKit +enum CategoryCollectionViewType { + case map + case place +} + final class CategoryCollectionView: UICollectionView { - convenience init() { - self.init(frame: .zero, collectionViewLayout: CategoryCollectionViewFlowLayout()) + convenience init(type: CategoryCollectionViewType) { + if type == .map { + self.init(frame: .zero, collectionViewLayout: CategoryCollectionViewFlowLayout()) + } else { + self.init(frame: .zero, collectionViewLayout: ThemeCollectionViewFlowLayout()) + } } required init?(coder: NSCoder) { @@ -27,8 +36,5 @@ final class CategoryCollectionView: UICollectionView { backgroundColor = .clear showsHorizontalScrollIndicator = false allowsMultipleSelection = false - register(MapCategoryCollectionViewCell.self, - forCellWithReuseIdentifier: MapCategoryCollectionViewCell.reuseIdentifier) } - } diff --git a/FindTown/FindTown/Presentation/PlaceScene/Flows/PlaceCoordinator.swift b/FindTown/FindTown/Presentation/PlaceScene/Flows/PlaceCoordinator.swift new file mode 100644 index 00000000..b7c99bd6 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Flows/PlaceCoordinator.swift @@ -0,0 +1,43 @@ +// +// PlaceCoordinator.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import UIKit + +import FindTownCore + +final class PlaceCoordinator: FlowCoordinator { + + var presentationStyle: PresentationStyle + weak var navigationController: UINavigationController? + let appDIContainer: AppDIContainer + + init( + presentationStyle: PresentationStyle, + appDIContainer: AppDIContainer + ) { + self.presentationStyle = presentationStyle + self.appDIContainer = appDIContainer + } + + internal func initScene() -> UIViewController { + let searchViewModel = PlaceViewModel(delegate: self) + let searchViewController = PlaceViewController(viewModel: searchViewModel) + return searchViewController + } +} + +extension PlaceCoordinator: PlaceViewModelDelegate { + func presentAddressSheet() { + guard let navigationController = navigationController else { return } + AddressSheetCoordinator( + presentationStyle: .present( + navigationController: navigationController, + modalPresentationStyle: .overFullScreen), + parentCoordinator: self + ).start() + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewController.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewController.swift new file mode 100644 index 00000000..2e6b2108 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewController.swift @@ -0,0 +1,189 @@ +// +// PlaceViewController.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import UIKit + +import FindTownCore +import FindTownUI + +import SnapKit +import RxSwift +import RxCocoa + +final class PlaceViewController: BaseViewController, UITableViewDelegate { + + // MARK: - Properties + + private let viewModel: PlaceViewModel? + private var placeTableViewHeightC: NSLayoutConstraint! + + // MARK: - Views + + private let indicator = UIActivityIndicatorView(style: .medium) + private let addressView = UIView() + private let addressButton: UIButton = { + let button = UIButton() + button.setTitleColor(FindTownColor.grey7.color, for: .normal) + button.titleLabel?.font = FindTownFont.label1.font + button.setImage(UIImage(named: "dropDown"), for: .normal) + button.semanticContentAttribute = .forceRightToLeft + return button + }() + + private let bannerCollectionView = BannerCollectionView() + private let realTimePlaceLabel = FindTownLabel( + text: "실시간 장소 제보", + font: .subtitle2) + private let themeCollectionView = CategoryCollectionView(type: .place) + private let placeTableView = PlaceTableView() + private let emptyView = EmptyView(type: .emptyPlace) + + // MARK: - Life Cycle + + init(viewModel: PlaceViewModel) { + self.viewModel = viewModel + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + placeTableViewHeightC.constant = placeTableView.intrinsicContentSize.height + } + + override func setupView() { + self.view.backgroundColor = .white + self.title = "플레이스" + addressView.backgroundColor = .white +// indicator.startAnimating() + themeCollectionView.register( + ThemeCollectionViewCell.self, + forCellWithReuseIdentifier: ThemeCollectionViewCell.reuseIdentifier + ) + // TODO: 추후 수정 + addressButton.setTitle("서울시 강남구 역삼동", for: .normal) + } + + override func addView() { + super.addView() + + [indicator, addressView].forEach { + self.view.addSubview($0) + } + + addressView.addSubview(addressButton) + + [ + bannerCollectionView, + realTimePlaceLabel, + themeCollectionView, + placeTableView, + emptyView + ].forEach { + stackView.addArrangedSubview($0) + } + + stackView.layoutMargins = UIEdgeInsets(top: 64, left: 16, bottom: 16, right: 16) + stackView.isLayoutMarginsRelativeArrangement = true + stackView.setCustomSpacing(40.0, after: bannerCollectionView) + stackView.setCustomSpacing(14.0, after: realTimePlaceLabel) + stackView.setCustomSpacing(24.0, after: themeCollectionView) + placeTableView.backgroundColor = .green + } + + override func setLayout() { + super.setLayout() + + let safeArea = self.view.safeAreaLayoutGuide + + indicator.snp.makeConstraints { + $0.centerX.centerY.equalToSuperview() + } + + addressView.snp.makeConstraints { + $0.top.leading.trailing.equalTo(safeArea) + $0.height.equalTo(54) + } + + addressButton.snp.makeConstraints { + $0.leading.equalToSuperview().inset(16) + $0.top.equalToSuperview().inset(24) + } + + bannerCollectionView.snp.makeConstraints { + $0.height.equalTo(80) + } + + themeCollectionView.snp.makeConstraints { + $0.height.equalTo(32+10) + } + + emptyView.snp.makeConstraints { + $0.height.equalTo(300) + } + + placeTableViewHeightC = placeTableView.heightAnchor.constraint(equalToConstant: 500) + placeTableViewHeightC.isActive = true + } + + override func bindViewModel() { + addressButton.rx.tap + .subscribe(onNext: { [weak self] in + self?.viewModel?.presentAddressSheet() + }) + .disposed(by: disposeBag) + + viewModel?.output.themeDataSource + .distinctUntilChanged() + .observe(on: MainScheduler.instance) + .bind(to: themeCollectionView.rx.items( + cellIdentifier: ThemeCollectionViewCell.reuseIdentifier, + cellType: ThemeCollectionViewCell.self)) { + index, item, cell in + cell.setupCell(title: item.description) + }.disposed(by: disposeBag) + + let mockData = BehaviorSubject<[UIImage]>(value: [UIImage(named: "banner1")!, + UIImage(named: "banner2")!, + UIImage(named: "banner1")!, + UIImage(named: "banner2")!]) + + mockData + .bind(to: bannerCollectionView.rx.items( + cellIdentifier: BannerCollectionViewCell.reuseIdentifier, + cellType: BannerCollectionViewCell.self)) { + index, item, cell in + cell.setupCell(image: item) + }.disposed(by: disposeBag) + + + // TODO: 추후 수정 + themeCollectionView.selectItem( + at: IndexPath(row: 0, section: 0), + animated: false, + scrollPosition: .bottom + ) + + mockData + .bind(to: placeTableView.rx.items( + cellIdentifier: PlaceTableViewCell.reuseIdentifier, + cellType: PlaceTableViewCell.self)) { + index, item, cell in +// cell.setupCell(image: item) + }.disposed(by: disposeBag) + + placeTableView.layoutIfNeeded() + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewModel.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewModel.swift new file mode 100644 index 00000000..8c3522be --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/PlaceViewModel.swift @@ -0,0 +1,47 @@ +// +// PlaceViewModel.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import Foundation + +import FindTownCore + +import RxSwift + +protocol PlaceViewModelDelegate { + func presentAddressSheet() +} + +protocol PlaceViewModelType { + func presentAddressSheet() +} + +final class PlaceViewModel: BaseViewModel { + + struct Output { + let themeDataSource = BehaviorSubject<[ThemaCategory]>(value: ThemaCategory.allCases) + } + + let delegate: PlaceViewModelDelegate + let output = Output() + + init(delegate: PlaceViewModelDelegate) { + self.delegate = delegate + + super.init() + self.bind() + } + + func bind() { +// self.output.themeDataSource.onNext(ThemaCategory.allCases) + } +} + +extension PlaceViewModel: PlaceViewModelType { + func presentAddressSheet() { + delegate.presentAddressSheet() + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionView.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionView.swift new file mode 100644 index 00000000..3a5578ad --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionView.swift @@ -0,0 +1,34 @@ +// +// BannerCollectionView.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import UIKit + +final class BannerCollectionView: UICollectionView { + + convenience init() { + self.init(frame: .zero, collectionViewLayout: BannerCollectionViewFlowLayout()) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { + super.init(frame: frame, collectionViewLayout: layout) + setupView() + } + + private func setupView() { + self.backgroundColor = .clear + self.showsHorizontalScrollIndicator = false + self.allowsMultipleSelection = false + self.register( + BannerCollectionViewCell.self, + forCellWithReuseIdentifier: BannerCollectionViewCell.reuseIdentifier) + } + +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewCell.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewCell.swift new file mode 100644 index 00000000..5b098c9c --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewCell.swift @@ -0,0 +1,57 @@ +// +// BannerCollectionViewCell.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import UIKit + +import FindTownUI + +import SnapKit + +final class BannerCollectionViewCell: UICollectionViewCell { + + // MARK: Properties + + static var reuseIdentifier: String { + return String(describing: self) + } + + private let imageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "banner1") + return imageView + }() + + func setupCell(image: UIImage) { + imageView.image = image + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupView() + setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension BannerCollectionViewCell { + func setupView() { + contentView.layer.cornerRadius = 16 + } + + func setupLayout() { + [imageView].forEach { + contentView.addSubview($0) + } + + imageView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewFlowLayout.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewFlowLayout.swift new file mode 100644 index 00000000..5ea608d3 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/BannerCollectionView/BannerCollectionViewFlowLayout.swift @@ -0,0 +1,30 @@ +// +// BannerCollectionViewFlowLayout.swift +// FindTown +// +// Created by 장선영 on 2023/11/08. +// + +import UIKit + +final class BannerCollectionViewFlowLayout: UICollectionViewFlowLayout { + + private let itemSpacing = 16.0 + + override init() { + super.init() + setupView() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + private func setupView() { + scrollDirection = .horizontal + minimumLineSpacing = itemSpacing + + let width = UIScreen.main.bounds.width - 16.0 * 2 + self.itemSize = CGSize(width: width, height: 80) + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableView.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableView.swift new file mode 100644 index 00000000..200eb81a --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableView.swift @@ -0,0 +1,40 @@ +// +// PlaceTableView.swift +// FindTown +// +// Created by 장선영 on 2023/12/03. +// + +import UIKit + +final class PlaceTableView: UITableView { + + override init(frame: CGRect, style: UITableView.Style) { + super.init(frame: frame, style: style) + + setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var intrinsicContentSize: CGSize { + return contentSize + } + + override var contentSize: CGSize { + didSet { + self.invalidateIntrinsicContentSize() + } + } + + private func setupView() { + self.separatorStyle = .none + self.rowHeight = UITableView.automaticDimension + self.isScrollEnabled = false + register(PlaceTableViewCell.self, + forCellReuseIdentifier: PlaceTableViewCell.reuseIdentifier) +// contentInset = UIEdgeInsets(top: 24, left: 0, bottom: 0, right: 0) + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableViewCell.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableViewCell.swift new file mode 100644 index 00000000..c5c68e12 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/PlaceTableView/PlaceTableViewCell.swift @@ -0,0 +1,153 @@ +// +// PlaceTableViewCell.swift +// FindTown +// +// Created by 장선영 on 2023/12/03. +// + +import UIKit + +import FindTownUI + +import SnapKit + +final class PlaceTableViewCell: UITableViewCell { + + // MARK: Properties + + static var reuseIdentifier: String { + return String(describing: self) + } + + let placeTipImageView = UIImageView() + let placeTitleLabel = FindTownLabel(text: "미정국수0410 멸치국수 잘하는집 신촌점 미정국수0410", font: .body1) + let viewMoreButton = UIButton() + let placeReviewView = UIView() + let reviewStackView = UIStackView() + let nameAndTimeView = UIView() + let nameLabel = FindTownLabel(text: "맛집왕님", font: .body3, textColor: .grey7) + let timeLabel = FindTownLabel(text: "1시간 전", font: .label2, textColor: .grey5) + let reviewLabel = FindTownLabel(text: "매장이 넓고 자리도 많아서 혼밥하기 딱 좋은 장소에요! 메뉴도 종류가 많아서 뭐먹을지 고민될 때에 방문하면 좋아요. 특히 오므라이스가 맛있었...", + font: .body3, textColor: .grey7) + + // MARK: - Life Cycle + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + addView() + setLayout() + setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupData(data: Any) { + + } + + override func layoutSubviews() { + super.layoutSubviews() + contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 0, + left: 0, + bottom: 32, + right: 0)) + } +} + +extension PlaceTableViewCell { + func addView() { + [placeTipImageView, + placeTitleLabel, + viewMoreButton, + placeReviewView].forEach { + contentView.addSubview($0) + } + +// [nameAndTimeView, reviewLabel].forEach { +//// reviewStackView.addArrangedSubview($0) +// placeReviewView.addSubview($0) +// } +// +// +//// placeReviewView.addSubview(reviewStackView) +// +// [nameLabel, timeLabel].forEach { +// nameAndTimeView.addSubview($0) +// } + } + + func setupView() { + self.backgroundColor = .white + self.selectionStyle = .none + + placeTipImageView.image = UIImage(named: "placeTip") + viewMoreButton.setTitle("리뷰 3개", for: .normal) + viewMoreButton.titleLabel?.font = FindTownFont.body3.font + viewMoreButton.setTitleColor(FindTownColor.grey6.color, for: .normal) + viewMoreButton.setImage(UIImage(named: "Icon_Navi"), for: .normal) + viewMoreButton.semanticContentAttribute = .forceRightToLeft + + placeReviewView.backgroundColor = .white + placeReviewView.layer.cornerRadius = 8 + placeReviewView.layer.borderWidth = 1 + placeReviewView.layer.borderColor = FindTownColor.back3.color.cgColor + placeReviewView.layer.addCustomShadow(shadowX: 0, + shadowY: 2, + shadowColor: FindTownColor.grey5.color, + blur: 3.0, + spread: 0.0, + alpha: 0.2) + + reviewStackView.axis = .vertical + reviewStackView.spacing = 6 + reviewLabel.numberOfLines = 2 + } + + func setLayout() { + placeTipImageView.snp.makeConstraints { + $0.height.width.equalTo(24) + $0.top.leading.equalTo(contentView) + } + + placeTitleLabel.snp.makeConstraints { + $0.leading.equalTo(placeTipImageView.snp.trailing).offset(4) + $0.trailing.equalTo(viewMoreButton.snp.leading).offset(-14) + $0.centerY.equalTo(placeTipImageView) + } + + viewMoreButton.snp.makeConstraints { + $0.centerY.equalTo(placeTipImageView) + $0.trailing.equalTo(contentView) + } + + placeReviewView.snp.makeConstraints { + $0.top.equalTo(placeTipImageView.snp.bottom).offset(16.0) + $0.leading.trailing.bottom.equalTo(contentView) + $0.height.equalTo(200) + } +// +// nameAndTimeView.snp.makeConstraints { +// $0.top.leading.trailing.equalToSuperview().inset(24.0) +// } +// +// nameLabel.snp.makeConstraints { +// $0.top.leading.equalTo(nameAndTimeView) +// } +// +// timeLabel.snp.makeConstraints { +// $0.leading.equalTo(nameLabel.snp.trailing).offset(6) +// $0.centerY.equalTo(nameLabel) +// } +// +// reviewLabel.snp.makeConstraints { +// $0.leading.trailing.equalTo(nameAndTimeView) +// $0.top.equalTo(nameAndTimeView.snp.bottom).offset(16) +// $0.bottom.equalToSuperview().inset(24) +// } +// +// reviewLabel.backgroundColor = .yellow + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewCell.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewCell.swift new file mode 100644 index 00000000..f0ee3473 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewCell.swift @@ -0,0 +1,130 @@ +// +// ThemeCollectionViewCell.swift +// FindTown +// +// Created by 장선영 on 2023/11/28. +// + +import UIKit +import FindTownUI + +import RxSwift +import SnapKit + +final class ThemeCollectionViewCell: UICollectionViewCell { + + static var reuseIdentifier: String { + return String(describing: self) + } + + private let stackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 6 + return stackView + }() + + private let imageView: UIImageView = { + let imageView = UIImageView() + imageView.tintColor = FindTownColor.grey5.color + return imageView + }() + + private let titleLabel: UILabel = { + let label = UILabel() + label.font = FindTownFont.body4.font + label.textColor = FindTownColor.grey6.color + return label + }() + + override func prepareForReuse() { + super.prepareForReuse() + + imageView.image = nil + titleLabel.text = "" + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupView() + setupLayout() + nonSelectedView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupCell(title: String) { + titleLabel.text = title + } + + override var isSelected: Bool { + didSet { + if isSelected { + selectedView() + } else { + nonSelectedView() + } + } + } + + override func layoutSubviews() { + super.layoutSubviews() + contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 10, + left: 0, + bottom: 15, + right: 0)) + } +} + +private extension ThemeCollectionViewCell { + + func setupView() { + contentView.backgroundColor = FindTownColor.white.color + contentView.layer.borderColor = FindTownColor.grey2.color.cgColor + contentView.layer.borderWidth = 1 + contentView.layer.cornerRadius = 16 + contentView.layer.masksToBounds = true + nonSelectedView() + } + + func setupLayout() { + + [stackView].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview($0) + } + + [titleLabel].forEach { + self.stackView.addArrangedSubview($0) + $0.translatesAutoresizingMaskIntoConstraints = false + } + + stackView.snp.makeConstraints { + $0.centerY.centerX.equalToSuperview() + $0.leading.trailing.equalToSuperview().inset(10) + } + + NSLayoutConstraint.activate([ + contentView.heightAnchor.constraint(equalToConstant: 57), + + imageView.widthAnchor.constraint(equalToConstant: 16.0), + imageView.heightAnchor.constraint(equalToConstant: 16.0), + ]) + } +} + +private extension ThemeCollectionViewCell { + func selectedView() { + contentView.backgroundColor = FindTownColor.grey7.color + contentView.layer.borderColor = FindTownColor.grey7.color.cgColor + titleLabel.textColor = FindTownColor.white.color + } + + func nonSelectedView() { + contentView.backgroundColor = FindTownColor.white.color + contentView.layer.borderColor = FindTownColor.grey4.color.cgColor + titleLabel.textColor = FindTownColor.grey6.color + } +} diff --git a/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewFlowLayout.swift b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewFlowLayout.swift new file mode 100644 index 00000000..88fea626 --- /dev/null +++ b/FindTown/FindTown/Presentation/PlaceScene/Place/SubViews/ThemeCollectionView/ThemeCollectionViewFlowLayout.swift @@ -0,0 +1,31 @@ +// +// ThemeCollectionViewFlowLayout.swift +// FindTown +// +// Created by 장선영 on 2023/11/27. +// + +import UIKit + +final class ThemeCollectionViewFlowLayout: UICollectionViewFlowLayout { + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override init() { + super.init() + + setupView() + } + + private func setupView() { + scrollDirection = .horizontal + minimumLineSpacing = 10 + sectionInset = UIEdgeInsets(top: 0.0, + left: 0.0, + bottom: 0.0, + right: 82.0) + estimatedItemSize = UICollectionViewFlowLayout.automaticSize + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Contents.json new file mode 100644 index 00000000..05042249 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Icon_Navi_Back-2.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Icon_Navi_Back-2.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Icon_Navi_Back-2.svg new file mode 100644 index 00000000..187d6749 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/Icon_Navi.imageset/Icon_Navi_Back-2.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/Contents.json new file mode 100644 index 00000000..b1203672 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "banner1.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/banner1.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/banner1.svg new file mode 100644 index 00000000..bcd148a7 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner1.imageset/banner1.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/Contents.json new file mode 100644 index 00000000..68108850 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "banner2.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/banner2.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/banner2.svg new file mode 100644 index 00000000..0e385f89 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/banner2.imageset/banner2.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/Contents.json new file mode 100644 index 00000000..839608a0 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_no place.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/ic_no place.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/ic_no place.svg new file mode 100644 index 00000000..6cb48ed1 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/ic_no place.imageset/ic_no place.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Contents.json new file mode 100644 index 00000000..0bf47562 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Frame 2608708-2.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Frame 2608708-2.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Frame 2608708-2.svg new file mode 100644 index 00000000..721bc852 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/PlaceVC/placeTip.imageset/Frame 2608708-2.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Contents.json index 022e2869..b4196fdb 100644 --- a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Contents.json +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "mapIcon.svg", + "filename" : "Icon_Btn_Map.svg", "idiom" : "universal", "scale" : "1x" }, diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Icon_Btn_Map.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Icon_Btn_Map.svg new file mode 100644 index 00000000..a8bee726 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/Icon_Btn_Map.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/mapIcon.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/mapIcon.svg deleted file mode 100644 index 548b2b81..00000000 --- a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/mapIcon.imageset/mapIcon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Contents.json b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Contents.json new file mode 100644 index 00000000..5d8734be --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Icon_Btn_Place.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Icon_Btn_Place.svg b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Icon_Btn_Place.svg new file mode 100644 index 00000000..2f93d312 --- /dev/null +++ b/FindTown/FindTown/Resource/Assets.xcassets/Image/TabBarVC/placeIcon.imageset/Icon_Btn_Place.svg @@ -0,0 +1,6 @@ + + + + + +