├── Pyonsnal-Color
├── .swiftlint.yml
├── Pyonsnal-Color
│ ├── Resource
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── Common
│ │ │ │ ├── Contents.json
│ │ │ │ ├── check.imageset
│ │ │ │ │ ├── check.svg
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_close.imageset
│ │ │ │ │ ├── icon_close.svg
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_title.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_arrow.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_detail.svg
│ │ │ │ ├── check.selected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── check.selected.svg
│ │ │ │ ├── check.selected.red.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_check_selected.svg
│ │ │ │ ├── icon_like_selected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_like_selected.svg
│ │ │ │ └── icon_like_unselected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_like_unselected.svg
│ │ │ ├── Filter
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_filter.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_filter.svg
│ │ │ │ ├── icon_filter_refresh.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_revert.svg
│ │ │ │ └── icon_filter_view.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_filter_view.svg
│ │ │ ├── Icon
│ │ │ │ ├── Contents.json
│ │ │ │ ├── logo.imageset
│ │ │ │ │ ├── logo.png
│ │ │ │ │ ├── logo@2x.png
│ │ │ │ │ ├── logo@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_header.imageset
│ │ │ │ │ ├── Frame 8907.png
│ │ │ │ │ ├── Frame 8907@2x.png
│ │ │ │ │ ├── Frame 8907@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_search.imageset
│ │ │ │ │ ├── icon_search.png
│ │ │ │ │ ├── icon_search@2x.png
│ │ │ │ │ ├── icon_search@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_pyonsnalColor.imageset
│ │ │ │ │ ├── icon_pyonsnalColor.png
│ │ │ │ │ ├── icon_pyonsnalColor@2x.png
│ │ │ │ │ ├── icon_pyonsnalColor@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_check.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_check.svg
│ │ │ │ ├── icon_delete.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_delete.svg
│ │ │ │ └── icon_delete_medium.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_delete(m).svg
│ │ │ ├── Others
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_delete.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_delete.svg
│ │ │ │ └── icon_revert.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_revert.svg
│ │ │ ├── Profile
│ │ │ │ ├── Contents.json
│ │ │ │ ├── profile_edit.imageset
│ │ │ │ │ ├── edit_24.png
│ │ │ │ │ ├── edit_24@2x.png
│ │ │ │ │ ├── edit_24@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ │ └── profile_plus.imageset
│ │ │ │ │ ├── profile_plus@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── Review
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_review.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_review.svg
│ │ │ │ ├── star_large.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── filled=unfilled, size=L.svg
│ │ │ │ ├── star_medium.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── filled=unfilled, size=m.svg
│ │ │ │ ├── star_filled_large.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── filled=filled, size=L.svg
│ │ │ │ ├── star_filled_medium.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── filled=filled, size=m.svg
│ │ │ │ ├── icon_thumbsDown_filled.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_thumbsDown_filled.svg
│ │ │ │ ├── icon_thumbsUp_filled.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_thumbsUp_filled.svg
│ │ │ │ ├── icon_thumbsUp_unfilled.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_thumbsUp_unfilled.svg
│ │ │ │ └── icon_thumbsDown_unfilled.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_thumbsDown_unfilled.svg
│ │ │ ├── Splash
│ │ │ │ ├── Contents.json
│ │ │ │ └── image_splash.imageset
│ │ │ │ │ ├── image_splash.png
│ │ │ │ │ ├── image_splash@2x.png
│ │ │ │ │ ├── image_splash@3x.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── TabBar
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_tab_my_selected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_tab_my_selected.svg
│ │ │ │ ├── icon_tab_home_selected.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_tab_my_unselected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_tab_my_unselected.svg
│ │ │ │ ├── icon_tab_sale_selected.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_tab_home_unselected.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_tab_sale_unselected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_tab_sale_unselected.svg
│ │ │ │ ├── icon_tab_favorite_selected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_tab_selected.svg
│ │ │ │ └── icon_tab_favorite_unselected.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_tab_unselected.svg
│ │ │ ├── login
│ │ │ │ ├── Contents.json
│ │ │ │ ├── login_apple.imageset
│ │ │ │ │ └── Contents.json
│ │ │ │ └── login_kakao.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── HeaderView
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_back.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_back.svg
│ │ │ │ └── bellSimple.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── BellSimple.svg
│ │ │ ├── ServiceTag
│ │ │ │ ├── Contents.json
│ │ │ │ └── tag_store.imageset
│ │ │ │ │ ├── tag_store.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── StoreLogo
│ │ │ │ ├── Contents.json
│ │ │ │ ├── store_logo_CU.imageset
│ │ │ │ │ ├── store logo_CU.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── store_logo_GS.imageset
│ │ │ │ │ ├── store logo_GS.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── store_logo_emart24.imageset
│ │ │ │ │ ├── store logo_emart24.png
│ │ │ │ │ └── Contents.json
│ │ │ │ └── store_logo_7-eleven.imageset
│ │ │ │ │ ├── store logo_GS_7-eleven.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── StoreTag
│ │ │ │ ├── Contents.json
│ │ │ │ ├── tag_store_CU.imageset
│ │ │ │ │ ├── tag_store_CU.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── tag_store_GS.imageset
│ │ │ │ │ ├── tag_store_GS.png
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── tag_store_7eleven.imageset
│ │ │ │ │ ├── tag_store_7eleven.png
│ │ │ │ │ └── Contents.json
│ │ │ │ └── tag_store_emart24.imageset
│ │ │ │ │ ├── tag_store_emart24.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── LineIconLarge
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon_share.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_share.svg
│ │ │ ├── LineIconMedium
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_close.imageset
│ │ │ │ │ ├── icon_close.svg
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_back.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_back.svg
│ │ │ │ ├── icon_next.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_next.svg
│ │ │ │ ├── icon_alarm.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_alarm.svg
│ │ │ │ └── icon_check.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_check.svg
│ │ │ ├── LineIconSmall
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon_close_small.imageset
│ │ │ │ │ ├── icon_close_small.svg
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── icon_detail.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_detail.svg
│ │ │ │ ├── icon_filter.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_filter.svg
│ │ │ │ └── icon_filter_view.imageset
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── icon_filter_view.svg
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── AppIcon.png
│ │ │ │ └── Contents.json
│ │ │ └── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ ├── Font
│ │ │ ├── Pretendard-Medium.otf
│ │ │ ├── Pretendard-Regular.otf
│ │ │ └── Pretendard-SemiBold.otf
│ │ ├── Constants
│ │ │ ├── Url
│ │ │ │ ├── ProfileUrl.swift
│ │ │ │ └── TermsOfUseUrl.swift
│ │ │ └── CommonConstants.swift
│ │ ├── ImageAssetKind
│ │ │ ├── ImageAssetKind+Splash.swift
│ │ │ ├── ImageAssetKind+HeaderView.swift
│ │ │ ├── ImageAssetKind+Profile.swift
│ │ │ ├── ImageAsset+Filter.swift
│ │ │ ├── ImageAssetKind+StoreTag.swift
│ │ │ ├── ImageAssetKind+StoreIcon.swift
│ │ │ ├── ImageAssetKind+TabBar.swift
│ │ │ ├── ImageAssetKind+Icon.swift
│ │ │ └── ImageAssetKind.swift
│ │ └── GoogleService-Info.plist
│ ├── Entity
│ │ ├── Common
│ │ │ ├── EmptyResponse.swift
│ │ │ ├── ProductType.swift
│ │ │ └── ErrorResponse.swift
│ │ ├── Review
│ │ │ ├── ReviewFeedKind.swift
│ │ │ ├── UserReviewInput.swift
│ │ │ ├── ReviewEvaluationState.swift
│ │ │ ├── ReviewHateCountEntity.swift
│ │ │ ├── ReviewLikeCountEntity.swift
│ │ │ ├── ReviewEvaluationProtocol.swift
│ │ │ ├── ReviewTasteEvaluation.swift
│ │ │ ├── ReviewQualityEvaluation.swift
│ │ │ ├── ReviewValueForMoneyEvaluation.swift
│ │ │ ├── ReviewUploadEntity.swift
│ │ │ └── ReviewEvaluationKind.swift
│ │ ├── Auth
│ │ │ ├── AuthType.swift
│ │ │ ├── UserLoginStatusEntity.swift
│ │ │ └── UserAuthEntity.swift
│ │ ├── Member
│ │ │ ├── NicknameEntity.swift
│ │ │ └── MemberInfoEntity.swift
│ │ ├── Products
│ │ │ ├── ProductDetailSection.swift
│ │ │ ├── ProductGiftEntity.swift
│ │ │ ├── ProductDetailSectionModel.swift
│ │ │ ├── SortEntity.swift
│ │ │ ├── ProductDetailSectionItem.swift
│ │ │ ├── PageableEntity.swift
│ │ │ ├── EventBannerEntity.swift
│ │ │ ├── ProductConvertable.swift
│ │ │ ├── ProductPageEntity.swift
│ │ │ ├── BrandProductEntity.swift
│ │ │ └── EventProductEntity.swift
│ │ ├── GiftItemEntity.swift
│ │ ├── Curation
│ │ │ ├── CurationEntity.swift
│ │ │ ├── EventImageEntity.swift
│ │ │ ├── EventBannerDetailEntity.swift
│ │ │ └── HomeBannerEntity.swift
│ │ ├── Filter
│ │ │ ├── FilterCellItem.swift
│ │ │ ├── FilterType.swift
│ │ │ └── FilterEntity.swift
│ │ └── EventTag.swift
│ ├── Extension
│ │ ├── NSObject+.swift
│ │ ├── UICollectionReusableView+.swift
│ │ ├── UIControl+.swift
│ │ ├── UIImage+.swift
│ │ ├── UITextField+.swift
│ │ ├── CALayer+.swift
│ │ ├── UILabel+.swift
│ │ ├── DateFormatter+.swift
│ │ ├── UITableView+.swift
│ │ ├── NSMutableAttributedString+.swift
│ │ ├── CGFloat+.swift
│ │ ├── CombineCocoa+.swift
│ │ ├── URLRequest+.swift
│ │ ├── UIImageView+.swift
│ │ ├── UICollectionView+.swift
│ │ ├── UIView+.swift
│ │ └── String+.swift
│ ├── Common
│ │ ├── Protocol
│ │ │ ├── ProductPresentable.swift
│ │ │ ├── ViewHolable.swift
│ │ │ ├── FavoriteHomeDelegate.swift
│ │ │ ├── ItemIdentifier.swift
│ │ │ ├── ClassNameRenderable.swift
│ │ │ ├── ProductListDelegate.swift
│ │ │ ├── CommonProductPageViewControllerRenderable.swift
│ │ │ ├── TopCollectionViewDatasource.swift
│ │ │ └── FilterRenderable.swift
│ │ ├── SearchBar
│ │ │ └── SearchBarViewDelegate.swift
│ │ ├── NavigationBar
│ │ │ ├── BackNavigationViewDelegate.swift
│ │ │ └── TitleNavigationViewDelegate.swift
│ │ ├── Popup
│ │ │ └── PopupViewDelegate.swift
│ │ ├── ReusableView
│ │ │ ├── SearchFilterHeaderDelegate.swift
│ │ │ ├── LoadingReusableView+ViewHolder.swift
│ │ │ ├── LoadingReusableView.swift
│ │ │ └── ItemHeaderTitleView.swift
│ │ ├── UserEvent
│ │ │ ├── UserEvent.swift
│ │ │ └── FoodChemistryEvent
│ │ │ │ └── FoodChemistryCell.swift
│ │ ├── Interface
│ │ │ └── CommonProduct.swift
│ │ ├── Combine
│ │ │ ├── ControlPublisher.swift
│ │ │ ├── GesturePublisher.swift
│ │ │ ├── ControlSubscription.swift
│ │ │ └── GestureSubscription.swift
│ │ ├── Footer
│ │ │ └── LineFooter.swift
│ │ ├── Button
│ │ │ ├── SortButton.swift
│ │ │ └── SelectionButton.swift
│ │ ├── Cell
│ │ │ └── EmptyCell.swift
│ │ └── BottomSheet
│ │ │ └── BottomSheetDismissAnimator.swift
│ ├── DetailReview
│ │ └── Review.swift
│ ├── ProductDetail
│ │ └── Subview
│ │ │ ├── ReviewWriteCell
│ │ │ └── ProductDetailReviewWriteCellDelegate.swift
│ │ │ └── ImageCell
│ │ │ ├── ProductDetailImageCell.swift
│ │ │ └── ProductDetailImageCell+ViewHolder.swift
│ ├── Application
│ │ └── AppComponent.swift
│ ├── Networking
│ │ ├── NetworkRequestable.swift
│ │ ├── Config
│ │ │ └── Config.swift
│ │ ├── Auth
│ │ │ └── AuthAPIService.swift
│ │ └── NetworkRequestBuilder.swift
│ ├── Pyonsnal-Color.entitlements
│ ├── Service
│ │ ├── AppInfoService.swift
│ │ ├── UserAuthService.swift
│ │ ├── KakaoLoginService.swift
│ │ └── UserInfoService.swift
│ ├── 3rdParty
│ │ └── SnapKit+.swift
│ ├── ProfileHome
│ │ └── SettingInfo.swift
│ ├── TermsOfUse
│ │ ├── SubTerms.swift
│ │ ├── TermsOfUseBuilder.swift
│ │ └── View
│ │ │ └── TermsButton.swift
│ ├── ReviewPopup
│ │ ├── ReviewPopupRouter.swift
│ │ └── ReviewPopupInteractor.swift
│ ├── CommonWeb
│ │ └── CommonWebRouter.swift
│ ├── LoginPopup
│ │ ├── LoginPopupRouter.swift
│ │ ├── LoginPopupBuilder.swift
│ │ ├── LoginPopupInteractor.swift
│ │ └── LoginPopupViewHolder.swift
│ ├── ProfileEdit
│ │ ├── ProfileEditRouter.swift
│ │ └── ProfileEditBuilder.swift
│ ├── LogoutPopup
│ │ └── LogoutPopupRouter.swift
│ ├── ProductFilter
│ │ ├── ProductFilterRouter.swift
│ │ ├── ProductFilterBuilder.swift
│ │ └── ProductFilterInteractor.swift
│ ├── NotificationList
│ │ ├── NotificationListRouter.swift
│ │ ├── NotificationListInteractor.swift
│ │ └── NotificationListBuilder.swift
│ ├── RootTabBar
│ │ ├── RootTabBarComponent.swift
│ │ └── RootTabBarInteractor.swift
│ ├── LoggedIn
│ │ ├── LoggedInInteractor.swift
│ │ └── LoggedInBuilder.swift
│ ├── ProductSearch
│ │ └── SortBottomSheet
│ │ │ └── ProductSearchSortBottomSheetRouter.swift
│ ├── DesignSystem
│ │ └── Spacing.swift
│ ├── ProductHome
│ │ └── Views
│ │ │ ├── ReusableView
│ │ │ ├── EventBannerHeaderView.swift
│ │ │ └── CurationFooterView.swift
│ │ │ └── Cell
│ │ │ └── CurationImageCell.swift
│ └── Root
│ │ ├── RootComponent.swift
│ │ └── RootBuilder.swift
└── Pyonsnal-Color.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ └── gamza.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── .github
└── PULL_REQUEST_TEMPLATE.md
/Pyonsnal-Color/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - trailing_whitespace
3 |
4 | line_length: 100
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Others/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/login/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/HeaderView/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/ServiceTag/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### 이슈
2 |
3 |
4 | ### 수정사항
5 |
6 |
7 | ### (기타, 스크린샷, 트러블슈팅) (선택 사항)
8 |
9 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconLarge/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-Medium.otf
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-Regular.otf
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-SemiBold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Font/Pretendard-SemiBold.otf
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/AppIcon.appiconset/AppIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/AppIcon.appiconset/AppIcon.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/logo@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Common/EmptyResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyResponse.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/08.
6 | //
7 |
8 | import Foundation
9 |
10 | struct EmptyResponse: Codable {}
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/NSObject+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/23.
6 | //
7 |
8 | import Foundation
9 |
10 | extension NSObject: ClassNameRenderable {}
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewFeedKind.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewFeedKind.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/03.
6 | //
7 |
8 | enum ReviewFeedKind {
9 | case good
10 | case bad
11 | }
12 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Frame 8907@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/icon_search@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/edit_24@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/ServiceTag/tag_store.imageset/tag_store.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/ServiceTag/tag_store.imageset/tag_store.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/ProductPresentable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductPresentable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/15.
6 | //
7 |
8 | protocol ProductPresentable {
9 | func didTabRootTabBar()
10 | }
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.imageset/check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_plus.imageset/profile_plus@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_plus.imageset/profile_plus@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/image_splash@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_CU.imageset/tag_store_CU.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_CU.imageset/tag_store_CU.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_GS.imageset/tag_store_GS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_GS.imageset/tag_store_GS.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_CU.imageset/store logo_CU.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_CU.imageset/store logo_CU.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_GS.imageset/store logo_GS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_GS.imageset/store logo_GS.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Auth/AuthType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthType.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/15.
6 | //
7 |
8 | import Foundation
9 |
10 | enum AuthType: String {
11 | case kakao
12 | case apple
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Member/NicknameEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NicknameEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/20/23.
6 | //
7 |
8 | import Foundation
9 |
10 | struct NicknameEntity: Codable {
11 | var nickname: String
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UICollectionReusableView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionReusableView+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/15.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UICollectionReusableView: ItemIdentifier {}
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor@2x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/icon_pyonsnalColor@3x.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_7eleven.imageset/tag_store_7eleven.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_7eleven.imageset/tag_store_7eleven.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_emart24.imageset/tag_store_emart24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_emart24.imageset/tag_store_emart24.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_emart24.imageset/store logo_emart24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_emart24.imageset/store logo_emart24.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/SearchBar/SearchBarViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchBarViewDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/21.
6 | //
7 |
8 | protocol SearchBarViewDelegate: AnyObject {
9 | func updateText(_ text: String?)
10 | }
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_close.imageset/icon_close.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_7-eleven.imageset/store logo_GS_7-eleven.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YAPP-Github/PyonsnalColor-iOS/HEAD/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_7-eleven.imageset/store logo_GS_7-eleven.png
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/NavigationBar/BackNavigationViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BackNavigationViewDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/01.
6 | //
7 |
8 | protocol BackNavigationViewDelegate: AnyObject {
9 | func didTapBackButton()
10 | }
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/DetailReview/Review.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Review.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/09/22.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Review {
11 | let kind: ReviewEvaluationKind
12 | let state: ReviewEvaluationState
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Auth/UserLoginStatusEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserLoginStatusEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/15.
6 | //
7 |
8 | import Foundation
9 |
10 | struct UserLoginStatusEntity: Decodable {
11 | var isJoined: Bool
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_title.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Layer_1.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_close.imageset/icon_close.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Common/ProductType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductType.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/16.
6 | //
7 |
8 | import Foundation
9 |
10 | enum ProductType: String, Decodable {
11 | case pb = "PB"
12 | case event = "EVENT"
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_detail.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_close.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_filter.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/HeaderView/icon_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_back.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_check.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_delete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_delete.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Others/icon_delete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_delete.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Others/icon_revert.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_revert.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_review.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_review.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/ServiceTag/tag_store.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tag_store.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/login/login_apple.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "login-apple.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/login/login_kakao.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "login_kakao.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_arrow.imageset/icon_detail.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/HeaderView/bellSimple.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BellSimple.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconLarge/icon_share.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_share.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_back.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_next.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_next.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_close_small.imageset/icon_close_small.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_CU.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tag_store_CU.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_GS.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tag_store_GS.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check.selected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter_refresh.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_revert.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter_view.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_filter_view.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_delete_medium.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_delete(m).svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_alarm.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_alarm.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_check.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_close.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_detail.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_detail.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_filter.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_filter.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_CU.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "store logo_CU.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_GS.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "store logo_GS.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.selected.red.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_check_selected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_next.imageset/icon_next.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_detail.imageset/icon_detail.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_filter.imageset/icon_filter.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "filled=unfilled, size=L.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_medium.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "filled=unfilled, size=m.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_7eleven.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tag_store_7eleven.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreTag/tag_store_emart24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tag_store_emart24.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/ViewHolable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewHolable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/10.
6 | //
7 |
8 | import UIKit
9 |
10 | protocol ViewHolderable {
11 | func place(in view: UIView)
12 | func configureConstraints(for view: UIView)
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailSection.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/17.
6 | //
7 |
8 | enum ProductDetailSection {
9 | case image
10 | case information
11 | case reviewWrite
12 | case review
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter.imageset/icon_filter.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_back.imageset/icon_back.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_close_small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_close_small.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_filter_view.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_filter_view.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_filled_large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "filled=filled, size=L.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_filled_medium.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "filled=filled, size=m.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_emart24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "store logo_emart24.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_my_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_my_selected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Popup/PopupViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupViewDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/31/24.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol PopupViewDelegate: AnyObject {
11 | func didTapConfirmButton()
12 | func didTapDismissButton()
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/ReusableView/SearchFilterHeaderDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchFilterHeaderDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/29.
6 | //
7 |
8 | protocol SearchFilterHeaderDelegate: AnyObject {
9 | func didTapSortButton(filterItem: FilterItemEntity)
10 | }
11 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_check.imageset/icon_check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/StoreLogo/store_logo_7-eleven.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "store logo_GS_7-eleven.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_home_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_home_selected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_my_unselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_my_unselected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_sale_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_sale_selected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/GiftItemEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GiftItemEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct GiftItemEntity: Decodable, Hashable {
11 | let name: String
12 | let price: String
13 | let imageURL: URL
14 | }
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductGiftEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductGiftEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/09.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ProductGiftEntity {
11 | let imageURL: URL
12 | let name: String
13 | let price: String
14 | }
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_home_unselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_home_unselected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_sale_unselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_sale_unselected.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Common/ErrorResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorResponse.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/03.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ErrorResponse: Decodable {
11 | let code: String?
12 | let message: String?
13 | let bodyString: String?
14 | }
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailSectionModel.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/18.
6 | //
7 |
8 | struct ProductDetailSectionModel {
9 | let section: ProductDetailSection
10 | let items: [ProductDetailSectionItem]
11 | }
12 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_check.imageset/icon_check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Auth/UserAuthEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserAuthEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/08.
6 | //
7 |
8 | struct UserAuthEntity: Codable {
9 | let isFirstLogin: Bool
10 | let isGuest: Bool
11 | let accessToken: String
12 | let refreshToken: String
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Constants/Url/ProfileUrl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileUrl.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/07.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ProfileUrl {
11 | static let team = "https://pentagonal-roquefort-ccf.notion.site/ae5a240aecf540f3bf8f0364aa15f7b7?pvs=4"
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/NavigationBar/TitleNavigationViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/04.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol TitleNavigationViewDelegate: AnyObject {
11 | func didTabSearchButton()
12 | func didTabNotificationButton()
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "AppIcon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/HeaderView/icon_back.imageset/icon_back.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/FavoriteHomeDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FavoriteHomeDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/11/23.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol FavoriteHomeDelegate: AnyObject {
11 | func didTapFavoriteButton(product: ProductDetailEntity, action: FavoriteButtonAction)
12 | }
13 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/UserReviewInput.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserReviewInput.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 12/28/23.
6 | //
7 |
8 | import UIKit
9 |
10 | struct UserReviewInput {
11 | let reviews: [ReviewEvaluationKind : ReviewEvaluationState]
12 | let reviewContents: String
13 | let reviewImage: UIImage?
14 | }
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewEvaluationState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewEvaluationState.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/18.
6 | //
7 |
8 | enum ReviewEvaluationState: String {
9 | case good = "GOOD"
10 | case normal = "NORMAL"
11 | case bad = "BAD"
12 | }
13 |
14 | extension ReviewEvaluationState: Codable {
15 | }
16 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ReviewWriteCell/ProductDetailReviewWriteCellDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailReviewWriteCellDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/09.
6 | //
7 |
8 | protocol ProductDetailReviewWriteCellDelegate: AnyObject {
9 | func writeButtonDidTap()
10 | func sortButtonDidTap()
11 | }
12 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewHateCountEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewHateCountEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/25.
6 | //
7 |
8 | struct ReviewHateCountEntity {
9 | let writerIds: [Int]
10 | let hateCount: Int
11 | }
12 |
13 | extension ReviewHateCountEntity: Hashable {}
14 | extension ReviewHateCountEntity: Codable {}
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewLikeCountEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewLikeCountEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/25.
6 | //
7 |
8 | struct ReviewLikeCountEntity {
9 | let writerIds: [Int]
10 | let likeCount: Int
11 | }
12 |
13 | extension ReviewLikeCountEntity: Hashable {}
14 | extension ReviewLikeCountEntity: Codable {}
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/UserEvent/UserEvent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserEvent.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/23/24.
6 | //
7 |
8 | import UIKit
9 |
10 | enum UserEvent: String, Decodable {
11 | case launchingEvent
12 | case foodChemistryEvent
13 | }
14 |
15 | struct UserEventDetail {
16 | let title: String
17 | let urlString: String
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.selected.imageset/check.selected.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewEvaluationProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewEvaluationProtocol.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/30.
6 | //
7 |
8 | protocol ReviewEvaluationProtocol {
9 | var name: String { get }
10 | var goodStateText: String { get }
11 | var normalStateText: String { get }
12 | var badStateText: String { get }
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UIControl+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | extension UIControl {
12 | func controlPublisher(for event: UIControl.Event) -> ControlPublisher {
13 | return ControlPublisher(control: self, controlEvent: event)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/check.selected.red.imageset/icon_check_selected.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewTasteEvaluation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewTasteEvaluation.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/29.
6 | //
7 |
8 | struct ReviewTasteEvaluation: ReviewEvaluationProtocol {
9 | let name: String = "맛"
10 | let goodStateText: String = "맛있어요"
11 | let normalStateText: String = "맛있어요"
12 | let badStateText: String = "맛있어요"
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewQualityEvaluation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewQualityEvaluation.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/29.
6 | //
7 |
8 | struct ReviewQualityEvaluation: ReviewEvaluationProtocol {
9 | let name: String = "맛"
10 | let goodStateText: String = "좋아요"
11 | let normalStateText: String = "보통이에요"
12 | let badStateText: String = "별로에요"
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_delete.imageset/icon_delete.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/ItemIdentifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemIdentifier.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/28.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol ItemIdentifier {
11 | static var identifier: String { get }
12 | }
13 |
14 | extension ItemIdentifier {
15 | static var identifier: String {
16 | return String(describing: self)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Others/icon_delete.imageset/icon_delete.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UIImage+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/09/22.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIImage {
11 | func resize(targetSize: CGSize) -> UIImage? {
12 | return UIGraphicsImageRenderer(size: targetSize).image { _ in
13 | draw(in: .init(origin: .zero, size: targetSize))
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Application/AppComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppComponent.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/05/28.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | final class AppComponent: Component, RootDependency {
11 | let userAuthService: UserAuthService = .init(keyChainService: .shared)
12 | init() {
13 | super.init(dependency: EmptyComponent())
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewValueForMoneyEvaluation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewValueForMoneyEvaluation.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/29.
6 | //
7 |
8 | struct ReviewValueForMoneyEvaluation: ReviewEvaluationProtocol {
9 | let name: String = "맛"
10 | let goodStateText: String = "맛있어요"
11 | let normalStateText: String = "맛있어요"
12 | let badStateText: String = "맛있어요"
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/ClassNameRenderable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClassNameRenderable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/26.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol ClassNameRenderable {
11 | static var className: String { get }
12 | }
13 |
14 | extension ClassNameRenderable {
15 | static var className: String {
16 | return String(describing: self)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Member/MemberInfoEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemberInfoEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/08.
6 | //
7 |
8 | import Foundation
9 |
10 | struct MemberInfoEntity: Decodable {
11 | var oauthId: String
12 | var oauthType: String
13 | var isGuest: Bool
14 | var profileImage: String?
15 | var memberId: Int
16 | var nickname: String
17 | var email: String
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewUploadEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewUploadEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/10/09.
6 | //
7 |
8 | import Foundation
9 |
10 | struct ReviewUploadEntity: Encodable {
11 | let taste: String
12 | let quality: String
13 | let valueForMoney: String
14 | let score: Double
15 | let contents: String
16 | let writerId: Int
17 | let writerName: String
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+Splash.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+Splash.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/08.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum Splash: String {
12 | case imageSplash = "image_splash"
13 |
14 | var image: UIImage? {
15 | return .init(named: self.rawValue)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Curation/CurationEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CurationEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct CurationProductsEntity: Decodable {
11 | let curationProducts: [CurationEntity]
12 | }
13 |
14 | struct CurationEntity: Decodable, Hashable {
15 | let title: String
16 | let subTitle: String
17 | let products: [ProductDetailEntity]
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/SortEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SortEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/08.
6 | //
7 |
8 | struct SortEntity: Decodable {
9 | let isEmpty: Bool
10 | let unsorted: Bool
11 | let isSorted: Bool
12 |
13 | private enum CodingKeys: String, CodingKey {
14 | case isEmpty = "empty"
15 | case unsorted
16 | case isSorted = "sorted"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UITextField+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/20/23.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UITextField {
11 | func addLeftPaddingView(point: Int) {
12 | let height = Int(self.frame.size.height)
13 | self.leftView = UIView(frame: CGRect(x: 0, y: 0, width: point, height: height))
14 | self.leftViewMode = .always
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Networking/NetworkRequestable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkRequestable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/03.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 | import Alamofire
11 |
12 | protocol NetworkRequestable {
13 | func request(
14 | _ urlRequest: NetworkRequestBuilder,
15 | model: T.Type
16 | ) -> AnyPublisher, Never>
17 | }
18 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+HeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+HeaderView.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/02.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum HeaderView: String {
12 | case iconBack = "icon_back"
13 |
14 | var image: UIImage? {
15 | return .init(named: self.rawValue)
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Curation/EventImageEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventImageEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 12/26/23.
6 | //
7 |
8 | import Foundation
9 |
10 | struct EventImageEntity: Decodable, Hashable {
11 | let title: String
12 | let bannerDetails: [EventBannerDetailEntity]
13 |
14 | private enum CodingKeys: String, CodingKey {
15 | case title
16 | case bannerDetails
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_delete_medium.imageset/icon_delete(m).svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Constants/Url/TermsOfUseUrl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermsOfUseUrl.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/07.
6 | //
7 |
8 | import Foundation
9 |
10 | struct TermsOfUseUrl {
11 | static let use = "https://pentagonal-roquefort-ccf.notion.site/d6b586f765a94348b3130430c22a6e48?pvs=4"
12 | static let privateInfo = "https://pentagonal-roquefort-ccf.notion.site/fc827743cd4a481298baa5435386c134?pvs=4"
13 | }
14 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductDetailSectionItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailSectionItem.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/17.
6 | //
7 |
8 | import Foundation
9 |
10 | enum ProductDetailSectionItem {
11 | case image(imageURL: URL)
12 | case information(product: ProductDetailEntity)
13 | case reviewWrite(score: Double, reviewsCount: Int, sortItem: FilterItemEntity)
14 | case review(productReview: ReviewEntity)
15 | }
16 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "profile_plus@3x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/CALayer+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/11.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CALayer {
11 | func applyShadow(color: UIColor, alpha: Float, width: CGFloat, height: CGFloat, blur: CGFloat) {
12 | shadowColor = color.cgColor
13 | shadowOpacity = alpha
14 | shadowOffset = CGSize(width: width, height: height)
15 | shadowRadius = blur
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Pyonsnal-Color.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.applesignin
6 |
7 | Default
8 |
9 | com.apple.developer.associated-domains
10 |
11 | applinks:pyonsnalcolor.store
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_like_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_like_selected.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+Profile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+Profile.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/16/23.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum Profile: String {
12 | case profileEdit = "profile_edit"
13 | case profilePlus = "profile_plus"
14 |
15 | var image: UIImage? {
16 | return .init(named: self.rawValue)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Service/AppInfoService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppInfoService.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/27.
6 | //
7 |
8 | import Foundation
9 |
10 | final class AppInfoService {
11 | private init() {}
12 | static let shared = AppInfoService()
13 |
14 | var appVersion: String? = {
15 | let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
16 | return appVersion
17 | }()
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_like_unselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_like_unselected.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsDown_filled.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_thumbsDown_filled.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsUp_filled.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_thumbsUp_filled.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsUp_unfilled.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_thumbsUp_unfilled.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_favorite_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_selected.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsDown_unfilled.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_thumbsDown_unfilled.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_favorite_unselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_unselected.svg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/3rdParty/SnapKit+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SnapKit+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/24.
6 | //
7 |
8 | import SnapKit
9 |
10 | extension ConstraintMakerEditable {
11 | @discardableResult
12 | func offset(_ spacing: Spacing) -> ConstraintMakerEditable {
13 | return offset(spacing.value)
14 | }
15 |
16 | @discardableResult
17 | func inset(_ spacing: Spacing) -> ConstraintMakerEditable {
18 | return inset(spacing.value)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "logo.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "logo@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "logo@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAsset+Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAsset+Filter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/22.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum Filter: String {
12 | case refreshFilter = "icon_filter_refresh"
13 | case sortFilter = "icon_filter_view"
14 | case filter = "icon_filter"
15 |
16 | var image: UIImage? {
17 | return .init(named: self.rawValue)
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProfileHome/SettingInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingInfo.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/12.
6 | //
7 |
8 | import Foundation
9 |
10 | struct SettingInfo {
11 | let title: String
12 |
13 | var infoUrl: Setting?
14 |
15 | enum Setting: String {
16 | case teams
17 | var urlString: String? {
18 | switch self {
19 | case .teams:
20 | return ProfileUrl.team
21 | }
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Profile/profile_edit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "edit_24.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "edit_24@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "edit_24@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_header.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Frame 8907.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "Frame 8907@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "Frame 8907@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_search.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_search.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "icon_search@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "icon_search@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/PageableEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageableEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/08.
6 | //
7 |
8 | struct PageableEntity: Decodable {
9 | let offset: Int
10 | let pageSize: Int
11 | let isPaged: Bool
12 | let pageNumber: Int
13 | let isUnpaged: Bool
14 |
15 | private enum CodingKeys: String, CodingKey {
16 | case offset
17 | case pageSize
18 | case isPaged = "paged"
19 | case pageNumber
20 | case isUnpaged = "unpaged"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Splash/image_splash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "image_splash.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "image_splash@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "image_splash@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Constants/CommonConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonConstants.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/13.
6 | //
7 |
8 | import Foundation
9 |
10 | struct CommonConstants {
11 | static let convenienceStore: [String] = ["CU", "GS25", "Emart24", "7-Eleven"]
12 | static let eventSectionHeaderTitle = "이달의 이벤트 💌"
13 | static let productSectionHeaderTitle = "차별화 상품 🍙"
14 | static let itemSectionHeaderTitle = "행사 상품 🎁"
15 | static let productHomeStore: [String] = ["PICK!"] + Self.convenienceStore
16 | }
17 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+StoreTag.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+StoreTag.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/03.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum StoreTag: String {
12 | case sevenEleven = "tag_store_7eleven"
13 | case cu = "tag_store_CU"
14 | case gs25 = "tag_store_GS"
15 | case emart24 = "tag_store_emart24"
16 |
17 | var image: UIImage? {
18 | return .init(named: self.rawValue)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/ProductListDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductListDelegate.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/09.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol ProductListDelegate: FavoriteHomeDelegate {
11 | func didLoadPageList(store: ConvenienceStore)
12 | func refreshByPull()
13 | func didSelect(with product: ProductDetailEntity?)
14 |
15 | func deleteKeywordFilter(_ filter: FilterItemEntity)
16 | func refreshFilterButton()
17 | func didAppearProductList()
18 | func didFinishUpdateSnapshot()
19 | }
20 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UILabel+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UILabel+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/09/27.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UILabel {
11 | func addAttributedString(newText: String,font: UIFont?, color: UIColor?) {
12 | guard let text = self.text else { return }
13 |
14 | let attributedString = NSMutableAttributedString(string: text)
15 | attributedString.appendAttributes(string: newText, font: font, color: color)
16 |
17 | self.attributedText = attributedString
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+StoreIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+StoreIcon.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/02.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum StoreIcon: String {
12 | case sevenEleven = "store_logo_7-eleven"
13 | case cu = "store_logo_CU"
14 | case emart24 = "store_logo_emart24"
15 | case gs25 = "store_logo_GS"
16 |
17 | var image: UIImage? {
18 | return .init(named: self.rawValue)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Icon/icon_pyonsnalColor.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_pyonsnalColor.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "icon_pyonsnalColor@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "icon_pyonsnalColor@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Interface/CommonProduct.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonProduct.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/03.
6 | //
7 |
8 | import UIKit
9 |
10 | // MARK: - Interface
11 | enum CommonProduct {
12 | enum Size {
13 | static let titleNavigationBarHeight: CGFloat = 48
14 | static let storeHeight: CGFloat = 44
15 | static let storeCollectionViewSeparatorHeight: CGFloat = 1
16 | static let filterMargin: UIEdgeInsets = .init(top: 12, left: 15, bottom: 12, right: 15)
17 | static let filterHeight: CGFloat = 56
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/UserEvent/FoodChemistryEvent/FoodChemistryCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FoodChemistryCell.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/23/24.
6 | //
7 |
8 | import UIKit
9 |
10 | final class FoodChemistryCell: UICollectionViewCell {
11 |
12 | override init(frame: CGRect) {
13 | super.init(frame: frame)
14 |
15 | configureView()
16 | }
17 |
18 | required init?(coder: NSCoder) {
19 | fatalError("init(coder:) has not been implemented")
20 | }
21 |
22 | private func configureView() {
23 | backgroundColor = .clear
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/CommonProductPageViewControllerRenderable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonProductPageViewControllerRenderable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/09.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol CommonProductPageViewControllerRenderable: FavoriteHomeDelegate {
11 | func updateSelectedStoreCell(index: Int)
12 | func didChangeStore(to store: ConvenienceStore)
13 | func didSelect(with brandProduct: ProductDetailEntity)
14 | func deleteKeywordFilter(_ filter: FilterItemEntity)
15 | func didTapRefreshFilterButton()
16 | func didFinishUpdateSnapshot()
17 | }
18 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconSmall/icon_filter_view.imageset/icon_filter_view.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/DateFormatter+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateFormatter+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/30.
6 | //
7 |
8 | import Foundation
9 |
10 | extension DateFormatter {
11 | static let notificationFormatter: DateFormatter = {
12 | let dateFormatter = DateFormatter()
13 | dateFormatter.dateFormat = "yyyy.mm.dd"
14 | return dateFormatter
15 | }()
16 |
17 | static let productLastUpdateFormatter: DateFormatter = {
18 | let dateFormatter = DateFormatter()
19 | dateFormatter.dateFormat = "yy.mm.dd"
20 | return dateFormatter
21 | }()
22 | }
23 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter_view.imageset/icon_filter_view.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Filter/FilterCellItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilterCellItem.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/25.
6 | //
7 |
8 | import Foundation
9 |
10 | struct FilterCellItem: Hashable {
11 | var filterUseType: FilterUseType = .category
12 | var filter: FilterEntity?
13 |
14 | static func == (lhs: FilterCellItem, rhs: FilterCellItem) -> Bool {
15 | return lhs.filter?.defaultText == rhs.filter?.defaultText && lhs.filter?.filterType == rhs.filter?.filterType && lhs.filter?.isSelected == rhs.filter?.isSelected
16 | }
17 |
18 | enum FilterUseType {
19 | case refresh
20 | case category
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/EventBannerEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventBannerEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/09.
6 | //
7 |
8 | import Foundation
9 |
10 | struct EventBannerEntity: Decodable, Hashable {
11 | let identifier: String
12 | let storeType: ConvenienceStore
13 | let thumbnailImageURL: String
14 | let imageURL: String?
15 | let title: String?
16 | let updatedTime: String
17 |
18 | private enum CodingKeys: String, CodingKey {
19 | case identifier = "id"
20 | case storeType
21 | case thumbnailImageURL = "thumbnailImage"
22 | case imageURL = "image"
23 | case title
24 | case updatedTime
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UITableView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/27.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UITableView {
11 | func register(_ cellClass: AnyClass) {
12 | register(cellClass.self, forCellReuseIdentifier: String(describing: cellClass.self))
13 | }
14 |
15 | func dequeueReusableCell(for indexPath: IndexPath) -> T {
16 | guard let cell = self.dequeueReusableCell(withIdentifier: T.identifier, for: indexPath) as? T else {
17 | fatalError("Unexpected identifier : \(T.identifier)")
18 | }
19 | return cell
20 | }
21 | }
22 |
23 | extension UITableViewCell: ItemIdentifier {}
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_like_unselected.imageset/icon_like_unselected.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/TermsOfUse/SubTerms.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermsOfUse.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/07.
6 | //
7 |
8 | import Foundation
9 |
10 | struct SubTerms {
11 | let title: String
12 | var hasNextPage: Bool = false
13 | var type: TermsOfUse
14 |
15 | enum TermsOfUse {
16 | case age
17 | case use
18 | case privateInfo
19 |
20 | var urlString: String? {
21 | switch self {
22 | case .age:
23 | return nil
24 | case .use:
25 | return TermsOfUseUrl.use
26 | case .privateInfo:
27 | return TermsOfUseUrl.privateInfo
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_favorite_unselected.imageset/icon_tab_unselected.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/NSMutableAttributedString+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableAttributedString+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/14.
6 | //
7 |
8 | import UIKit
9 |
10 | extension NSMutableAttributedString {
11 |
12 | /// 특정 문자열의 color와 font 속성을 부여합니다.
13 | /// - Parameter font: 적용할 font 속성 값
14 | /// - Parameter color: 적용할 color 속성 값
15 | func appendAttributes(
16 | string: String,
17 | font: UIFont?,
18 | color: UIColor?
19 | ) {
20 | var attr: [NSAttributedString.Key: Any] = [:]
21 | attr[.font] = font
22 | attr[.foregroundColor] = color
23 | self.append(NSAttributedString(
24 | string: string,
25 | attributes: attr)
26 | )
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_favorite_selected.imageset/icon_tab_selected.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Others/icon_revert.imageset/icon_revert.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Common/icon_like_selected.imageset/icon_like_selected.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Filter/icon_filter_refresh.imageset/icon_revert.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductConvertable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductConvertable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/08.
6 | //
7 |
8 | import UIKit
9 |
10 | protocol ProductConvertable: Decodable, Hashable {
11 | var productId: String { get }
12 | var imageURL: URL { get }
13 | var storeType: ConvenienceStore { get }
14 | var updatedTime: String { get }
15 | var name: String { get }
16 | var price: String { get }
17 | var description: String? { get }
18 | var eventType: EventTag? { get }
19 | var productType: ProductType { get }
20 | var isFavorite: Bool? { get }
21 | var isNew: Bool? { get }
22 | }
23 |
24 | extension ProductConvertable {
25 | func hash(into hasher: inout Hasher) {
26 | hasher.combine(productId)
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconLarge/icon_share.imageset/icon_share.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/TopCollectionViewDatasource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopCollectionViewDatasource.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/23.
6 | //
7 |
8 | import UIKit
9 |
10 | class TopCollectionViewDatasource {
11 | enum SectionType: Hashable {
12 | case convenienceStore(store: [String])
13 | }
14 |
15 | enum ItemType: Hashable {
16 | case convenienceStore(storeName: String)
17 | }
18 |
19 | enum FilterSection: Hashable {
20 | case filter
21 | }
22 |
23 | enum FilterItem: Hashable {
24 | case filter(filterItem: FilterCellItem)
25 | }
26 |
27 | typealias StoreDataSource = UICollectionViewDiffableDataSource
28 | typealias FilterDataSource = UICollectionViewDiffableDataSource
29 | }
30 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_large.imageset/filled=unfilled, size=L.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_medium.imageset/filled=unfilled, size=m.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/EventTag.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventTag.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/04.
6 | //
7 |
8 | enum EventTag: String, Decodable {
9 | case discount = "DISCOUNT"
10 | case freebie = "GIFT"
11 | case onePlusOne = "ONE_TO_ONE"
12 | case twoPlusOne = "TWO_TO_ONE"
13 | case threePlusOne = "THREE_TO_ONE"
14 | case none = "NONE"
15 | }
16 |
17 | extension EventTag {
18 | var name: String? {
19 | switch self {
20 | case .discount:
21 | return "할인"
22 | case .freebie:
23 | return "증정"
24 | case .onePlusOne:
25 | return "1+1"
26 | case .twoPlusOne:
27 | return "2+1"
28 | case .threePlusOne:
29 | return "3+1"
30 | case .none:
31 | return ""
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+TabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+TabBar.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/27.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum TabBar: String {
12 | case homeSelected = "icon_tab_home_selected"
13 | case homeUnselected = "icon_tab_home_unselected"
14 | case mySelected = "icon_tab_my_selected"
15 | case myUnselected = "icon_tab_my_unselected"
16 | case favoriteSelected = "icon_tab_favorite_selected"
17 | case favoriteUnSelected = "icon_tab_favorite_unselected"
18 | case eventSelected = "icon_tab_sale_selected"
19 | case eventUnselected = "icon_tab_sale_unselected"
20 |
21 | var image: UIImage? {
22 | return .init(named: self.rawValue)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Protocol/FilterRenderable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilterRenderable.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/08/26.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol FilterRenderable {
11 | var filterStateManager: FilterStateManager? { get set }
12 | var filterDataEntity: FilterDataEntity? { get }
13 | var selectedFilterCodeList: [Int] { get }
14 | var selectedFilterKeywordList: [FilterItemEntity]? { get }
15 | var isNeedToShowRefreshFilterCell: Bool { get }
16 | func didSelectFilter(_ filterEntity: FilterEntity?)
17 | func didTapRefreshFilterCell()
18 | func requestwithUpdatedKeywordFilter()
19 | func initializeFilterState()
20 | func updateFiltersState(with filters: [FilterItemEntity], type: FilterType)
21 | func deleteKeywordFilter(_ filter: FilterItemEntity)
22 | func resetFilterState()
23 | }
24 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Curation/EventBannerDetailEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventBannerDetailEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/19/24.
6 | //
7 |
8 | import UIKit
9 |
10 | struct EventBannerDetailEntity: Decodable, Hashable {
11 | let userEvent: UserEvent
12 | let thumbnailImage: String
13 | let detailImage: String
14 | let links: [String]
15 |
16 | enum CodingKeys: CodingKey {
17 | case userEvent
18 | case thumbnailImage
19 | case detailImage
20 | case links
21 | }
22 | }
23 |
24 | extension EventBannerDetailEntity {
25 | /*
26 | var view: UIView? {
27 | switch userEvent {
28 | case .foodChemistryEvent:
29 | return FoodChemistryEventView(links: links)
30 | case .launchingEvent:
31 | return nil
32 | }
33 | }
34 | */
35 | }
36 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsUp_unfilled.imageset/icon_thumbsUp_unfilled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/CGFloat+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloat+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/24.
6 | //
7 |
8 | import Foundation
9 |
10 | extension CGFloat {
11 | static let spacing2: CGFloat = Spacing.spacing2.value
12 | static let spacing4: CGFloat = Spacing.spacing4.value
13 | static let spacing6: CGFloat = Spacing.spacing6.value
14 | static let spacing8: CGFloat = Spacing.spacing8.value
15 | static let spacing10: CGFloat = Spacing.spacing10.value
16 | static let spacing12: CGFloat = Spacing.spacing12.value
17 | static let spacing16: CGFloat = Spacing.spacing16.value
18 | static let spacing20: CGFloat = Spacing.spacing20.value
19 | static let spacing24: CGFloat = Spacing.spacing24.value
20 | static let spacing32: CGFloat = Spacing.spacing32.value
21 | static let spacing40: CGFloat = Spacing.spacing40.value
22 | }
23 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ReviewPopup/ReviewPopupRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewPopupRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/09/21.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ReviewPopupInteractable: Interactable {
11 | var router: ReviewPopupRouting? { get set }
12 | var listener: ReviewPopupListener? { get set }
13 | }
14 |
15 | protocol ReviewPopupViewControllable: ViewControllable {
16 | }
17 |
18 | final class ReviewPopupRouter: ViewableRouter,
20 | ReviewPopupRouting {
21 |
22 | override init(
23 | interactor: ReviewPopupInteractable,
24 | viewController: ReviewPopupViewControllable
25 | ) {
26 | super.init(interactor: interactor, viewController: viewController)
27 | interactor.router = self
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/ProductPageEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductPageEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/08.
6 | //
7 |
8 | struct ProductPageEntity: Decodable {
9 | let totalPages: Int?
10 | let totalElements: Int?
11 | let size: Int
12 | let content: [ProductDetailEntity]
13 | let number: Int
14 | let sort: SortEntity
15 | let isFirst: Bool
16 | let isLast: Bool
17 | let numberOfElements: Int
18 | let pageable: PageableEntity
19 | let isEmpty: Bool
20 |
21 | private enum CodingKeys: String, CodingKey {
22 | case totalPages
23 | case totalElements
24 | case size
25 | case content
26 | case number
27 | case sort
28 | case isFirst = "first"
29 | case isLast = "last"
30 | case numberOfElements
31 | case pageable
32 | case isEmpty = "empty"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_my_unselected.imageset/icon_tab_my_unselected.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/CommonWeb/CommonWebRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CommonWebRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/07.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol CommonWebInteractable: Interactable {
11 | var router: CommonWebRouting? { get set }
12 | var listener: CommonWebListener? { get set }
13 | }
14 |
15 | protocol CommonWebViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class CommonWebRouter: ViewableRouter, CommonWebRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: CommonWebInteractable, viewController: CommonWebViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Combine/ControlPublisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ControlPublisher.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | struct ControlPublisher: Publisher {
12 | typealias Output = UIControl
13 | typealias Failure = Never
14 |
15 | private let control: UIControl
16 | private let controlEvent: UIControl.Event
17 |
18 | init(control: UIControl, controlEvent: UIControl.Event) {
19 | self.control = control
20 | self.controlEvent = controlEvent
21 | }
22 |
23 | func receive(subscriber: S) where S: Subscriber, Never == S.Failure, UIControl == S.Input {
24 | let subscription = ControlSubscription(
25 | subscriber: subscriber,
26 | control: control,
27 | controlEvent: controlEvent
28 | )
29 | subscriber.receive(subscription: subscription)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoginPopup/LoginPopupRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginPopupRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/31/24.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LoginPopupInteractable: Interactable {
11 | var router: LoginPopupRouting? { get set }
12 | var listener: LoginPopupListener? { get set }
13 | }
14 |
15 | protocol LoginPopupViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class LoginPopupRouter: ViewableRouter, LoginPopupRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: LoginPopupInteractable, viewController: LoginPopupViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Combine/GesturePublisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GesturePublisher.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | struct GesturePublisher: Publisher {
12 |
13 | typealias Output = UIGestureRecognizer
14 | typealias Failure = Never
15 |
16 | private weak var targetView: UIView?
17 | private let gestureRecognizer: UIGestureRecognizer
18 |
19 | init(targetView: UIView, gestureRecognizer: UIGestureRecognizer) {
20 | self.targetView = targetView
21 | self.gestureRecognizer = gestureRecognizer
22 | }
23 |
24 | func receive(subscriber: S) where S : Subscriber, Never == S.Failure, UIGestureRecognizer == S.Input {
25 | let subscription = GestureSubscription(subscriber: subscriber, view: targetView, gestureRecognizer: gestureRecognizer)
26 | subscriber.receive(subscription: subscription)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProfileEdit/ProfileEditRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileEditRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/16/23.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProfileEditInteractable: Interactable {
11 | var router: ProfileEditRouting? { get set }
12 | var listener: ProfileEditListener? { get set }
13 | }
14 |
15 | protocol ProfileEditViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class ProfileEditRouter: ViewableRouter, ProfileEditRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: ProfileEditInteractable, viewController: ProfileEditViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LogoutPopup/LogoutPopupRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LogoutPopupRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/07.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LogoutPopupInteractable: Interactable {
11 | var router: LogoutPopupRouting? { get set }
12 | var listener: LogoutPopupListener? { get set }
13 | }
14 |
15 | protocol LogoutPopupViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class LogoutPopupRouter: ViewableRouter, LogoutPopupRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: LogoutPopupInteractable, viewController: LogoutPopupViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/ReusableView/LoadingReusableView+ViewHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingReusableView+ViewHolder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/23.
6 | //
7 |
8 | import UIKit
9 |
10 | extension LoadingReusableView {
11 | final class ViewHolder: ViewHolderable {
12 | // MARK: - UI Component
13 | let indicatorView: UIActivityIndicatorView = {
14 | let indicatorView = UIActivityIndicatorView()
15 | indicatorView.color = .gray500
16 | return indicatorView
17 | }()
18 |
19 | // MARK: - Interface
20 | func place(in view: UIView) {
21 | view.addSubview(indicatorView)
22 | }
23 |
24 | func configureConstraints(for view: UIView) {
25 | indicatorView.snp.makeConstraints { make in
26 | make.size.equalTo(44)
27 | make.center.equalToSuperview()
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsUp_filled.imageset/icon_thumbsUp_filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/BrandProductEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BrandProductEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/08.
6 | //
7 |
8 | import Foundation
9 |
10 | struct BrandProductEntity: Decodable, ProductConvertable, Hashable {
11 | let productId: String
12 | let imageURL: URL
13 | let storeType: ConvenienceStore
14 | let updatedTime: String
15 | let name: String
16 | let price: String
17 | let description: String?
18 | let eventType: EventTag?
19 | let productType: ProductType
20 | let isFavorite: Bool?
21 | let isNew: Bool?
22 |
23 | private enum CodingKeys: String, CodingKey {
24 | case productId = "id"
25 | case imageURL = "image"
26 | case storeType
27 | case updatedTime
28 | case name
29 | case price
30 | case description
31 | case eventType
32 | case productType
33 | case isFavorite
34 | case isNew
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductFilter/ProductFilterRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductFilterRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/25.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProductFilterInteractable: Interactable {
11 | var router: ProductFilterRouting? { get set }
12 | var listener: ProductFilterListener? { get set }
13 | }
14 |
15 | protocol ProductFilterViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class ProductFilterRouter: ViewableRouter, ProductFilterRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: ProductFilterInteractable, viewController: ProductFilterViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind+Icon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind+Icon.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/07.
6 | //
7 |
8 | import UIKit
9 |
10 | extension ImageAssetKind {
11 | enum Icon: String {
12 | case iconHeader = "icon_header"
13 | case iconPyonsnalColor = "icon_pyonsnalColor"
14 | case iconSearch = "icon_search"
15 | case iconDelete = "icon_delete"
16 | case iconDeleteMedium = "icon_delete_medium"
17 | case iconCheck = "icon_check"
18 | case iconReview = "icon_review"
19 | case iconThumbsDownFilled = "icon_thumbsDown_filled"
20 | case iconThumbsDownUnfilled = "icon_thumbsDown_unfilled"
21 | case iconThumbsUpFilled = "icon_thumbsUp_filled"
22 | case iconThumbsUpUnfilled = "icon_thumbsUp_unfilled"
23 | }
24 | }
25 |
26 | extension ImageAssetKind.Icon {
27 | var image: UIImage? {
28 | return UIImage(named: self.rawValue)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsDown_unfilled.imageset/icon_thumbsDown_unfilled.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/NotificationList/NotificationListRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationListRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/27.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol NotificationListInteractable: Interactable {
11 | var router: NotificationListRouting? { get set }
12 | var listener: NotificationListListener? { get set }
13 | }
14 |
15 | protocol NotificationListViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class NotificationListRouter: ViewableRouter, NotificationListRouting {
20 |
21 | // TODO: Constructor inject child builder protocols to allow building children.
22 | override init(interactor: NotificationListInteractable, viewController: NotificationListViewControllable) {
23 | super.init(interactor: interactor, viewController: viewController)
24 | interactor.router = self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | API_KEY
6 | AIzaSyApvMbQmUm1wedGAB0jFWEkc52A95uo07g
7 | GCM_SENDER_ID
8 | 251124560897
9 | PLIST_VERSION
10 | 1
11 | BUNDLE_ID
12 | kr.co.yapp.22th.pyonsnalcolor
13 | PROJECT_ID
14 | pyonsnalcolor-6ff5d
15 | STORAGE_BUCKET
16 | pyonsnalcolor-6ff5d.appspot.com
17 | IS_ADS_ENABLED
18 |
19 | IS_ANALYTICS_ENABLED
20 |
21 | IS_APPINVITE_ENABLED
22 |
23 | IS_GCM_ENABLED
24 |
25 | IS_SIGNIN_ENABLED
26 |
27 | GOOGLE_APP_ID
28 | 1:251124560897:ios:5312e33e8cfb72088efc00
29 |
30 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_thumbsDown_filled.imageset/icon_thumbsDown_filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/RootTabBar/RootTabBarComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootTabBarComponent.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/10.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | final class RootTabBarComponent: Component {
11 | }
12 |
13 | extension RootTabBarComponent: ProductHomeDependency,
14 | EventHomeDependency,
15 | FavoriteHomeDependency,
16 | ProfileHomeDependency {
17 |
18 | var client: PyonsnalColorClient {
19 | return PyonsnalColorClient()
20 | }
21 | var userAuthService: UserAuthService {
22 | return UserAuthService(keyChainService: KeyChainService.shared)
23 | }
24 |
25 | var favoriteAPIService: FavoriteAPIService {
26 | return FavoriteAPIService(client: client, userAuthService: userAuthService)
27 | }
28 |
29 | var productAPIService: ProductAPIService {
30 | return ProductAPIService(client: client, userAuthService: userAuthService)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/ReusableView/LoadingReusableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingReusableView.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/23.
6 | //
7 |
8 | import UIKit
9 |
10 | final class LoadingReusableView: UICollectionReusableView {
11 |
12 | // MARK: - Private Property
13 | private let viewHolder: ViewHolder = .init()
14 |
15 | // MARK: - Initailzer
16 | override init(frame: CGRect) {
17 | super.init(frame: frame)
18 |
19 | configureView()
20 | configureConstraint()
21 | configureUI()
22 | }
23 |
24 | required init?(coder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | // MARK: - Private Method
29 | private func configureView() {
30 | viewHolder.place(in: self)
31 | }
32 |
33 | private func configureConstraint() {
34 | viewHolder.configureConstraints(for: self)
35 | }
36 |
37 | private func configureUI() {
38 | viewHolder.indicatorView.startAnimating()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoggedIn/LoggedInInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoggedInInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/10.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LoggedInRouting: Routing {
11 | func cleanupViews()
12 | func attachRootTabBar()
13 | }
14 |
15 | protocol LoggedInListener: AnyObject {
16 | func routeToLoggedOutFromLoggedIn()
17 | func routeToLoggedInFromLoggedOut()
18 | }
19 |
20 | final class LoggedInInteractor: Interactor, LoggedInInteractable {
21 |
22 | weak var router: LoggedInRouting?
23 | weak var listener: LoggedInListener?
24 |
25 | override init() {}
26 |
27 | override func didBecomeActive() {
28 | super.didBecomeActive()
29 | }
30 |
31 | override func willResignActive() {
32 | super.willResignActive()
33 | router?.cleanupViews()
34 | }
35 |
36 | func routeToLoggedOut() {
37 | listener?.routeToLoggedOutFromLoggedIn()
38 | }
39 |
40 | func routeToLoggedIn() {
41 | listener?.routeToLoggedInFromLoggedOut()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductSearch/SortBottomSheet/ProductSearchSortBottomSheetRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductSearchSortBottomSheetRouter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/30.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProductSearchSortBottomSheetInteractable: Interactable {
11 | var router: ProductSearchSortBottomSheetRouting? { get set }
12 | var listener: ProductSearchSortBottomSheetListener? { get set }
13 | }
14 |
15 | protocol ProductSearchSortBottomSheetViewControllable: ViewControllable {
16 | // TODO: Declare methods the router invokes to manipulate the view hierarchy.
17 | }
18 |
19 | final class ProductSearchSortBottomSheetRouter: ViewableRouter, ProductSearchSortBottomSheetRouting {
20 |
21 | override init(interactor: ProductSearchSortBottomSheetInteractable, viewController: ProductSearchSortBottomSheetViewControllable) {
22 | super.init(interactor: interactor, viewController: viewController)
23 | interactor.router = self
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/DesignSystem/Spacing.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Spacing.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/24.
6 | //
7 |
8 | import UIKit
9 |
10 | struct Spacing {
11 | let value: CGFloat
12 |
13 | private init(value: CGFloat) {
14 | self.value = value
15 | }
16 |
17 | var negative: Spacing {
18 | Spacing(value: -value)
19 | }
20 | }
21 |
22 | extension Spacing {
23 | static let spacing2: Spacing = .init(value: 2)
24 | static let spacing4: Spacing = .init(value: 4)
25 | static let spacing6: Spacing = .init(value: 6)
26 | static let spacing8: Spacing = .init(value: 8)
27 | static let spacing10: Spacing = .init(value: 10)
28 | static let spacing12: Spacing = .init(value: 12)
29 | static let spacing16: Spacing = .init(value: 16)
30 | static let spacing20: Spacing = .init(value: 20)
31 | static let spacing24: Spacing = .init(value: 24)
32 | static let spacing28: Spacing = .init(value: 28)
33 | static let spacing32: Spacing = .init(value: 32)
34 | static let spacing40: Spacing = .init(value: 40)
35 | }
36 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/HeaderView/bellSimple.imageset/BellSimple.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/LineIconMedium/icon_alarm.imageset/icon_alarm.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Footer/LineFooter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineFooter.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/10.
6 | //
7 |
8 | import UIKit
9 |
10 | import SnapKit
11 |
12 | final class LineFooter: UICollectionReusableView {
13 |
14 | // MARK: - UI Component
15 |
16 | private let contentView: UIView = {
17 | let view = UIView()
18 | view.backgroundColor = .gray100
19 | return view
20 | }()
21 |
22 | // MARK: - Initailzer
23 |
24 | override init(frame: CGRect) {
25 | super.init(frame: frame)
26 |
27 | configureViews()
28 | configureConstraints()
29 | }
30 |
31 | required init?(coder: NSCoder) {
32 | fatalError("init(coder:) has not been implemented")
33 | }
34 |
35 | // MARK: - Override Method
36 |
37 | private func configureViews() {
38 | addSubview(contentView)
39 | }
40 |
41 | private func configureConstraints() {
42 | contentView.snp.makeConstraints { make in
43 | make.edges.equalToSuperview()
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/CombineCocoa+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CombineCocoa+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | extension UIButton {
12 | var tapPublisher: AnyPublisher {
13 | return controlPublisher(for: .touchUpInside)
14 | .map { _ in }
15 | .eraseToAnyPublisher()
16 | }
17 | }
18 |
19 | extension UITextField {
20 | var textPublisher: AnyPublisher {
21 | return controlPublisher(for: .editingChanged)
22 | .compactMap { $0 as? UITextField }
23 | .map { $0.text }
24 | .eraseToAnyPublisher()
25 | }
26 | }
27 |
28 | extension UIView {
29 | func gesturePublisher(with delegate: UIGestureRecognizerDelegate? = nil) -> GesturePublisher {
30 | /// 현재는 tapGesture가 default. 추후 다른 gesture가 필요로 되면 gestureRecognizer 확장하여 사용.
31 | let gestureRecognizer = UITapGestureRecognizer()
32 | gestureRecognizer.delegate = delegate
33 | return GesturePublisher(targetView: self, gestureRecognizer: gestureRecognizer)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductHome/Views/ReusableView/EventBannerHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventBannerHeaderView.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 12/27/23.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | final class EventBannerHeaderView: UICollectionReusableView {
12 | private let titleLabel: UILabel = {
13 | let label = UILabel()
14 | label.font = .title2
15 | label.textColor = .black
16 | return label
17 | }()
18 |
19 | override init(frame: CGRect) {
20 | super.init(frame: .zero)
21 |
22 | configureLayout()
23 | }
24 |
25 | required init?(coder: NSCoder) {
26 | fatalError("init(coder:) has not been implemented")
27 | }
28 |
29 | func configureHeaderView(title: String) {
30 | titleLabel.text = title
31 | }
32 |
33 | private func configureLayout() {
34 | addSubview(titleLabel)
35 |
36 | titleLabel.snp.makeConstraints { make in
37 | make.leading.bottom.equalToSuperview()
38 | make.height.equalTo(titleLabel.font.customLineHeight)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Filter/FilterType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilterType.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/25.
6 | //
7 |
8 | import Foundation
9 |
10 | enum FilterType: Decodable {
11 | case sort // 정렬
12 | case recommend // 상품 추천
13 | case category // 카테고리
14 | case event // 행사
15 | case unknown
16 |
17 | init(from decoder: Decoder) throws {
18 | let container = try decoder.singleValueContainer()
19 | let type = try? container.decode(String.self)
20 | switch type {
21 | case "sort": self = .sort
22 | case "recommend": self = .recommend
23 | case "category": self = .category
24 | case "event": self = .event
25 | default: self = .unknown
26 | }
27 | }
28 |
29 | var filterDefaultText: String {
30 | switch self {
31 | case .sort:
32 | return "최신순"
33 | case .recommend:
34 | return "상품 추천"
35 | case .category:
36 | return "카테고리"
37 | case .event:
38 | return "행사"
39 | case .unknown:
40 | return ""
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/URLRequest+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLRequest+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/06.
6 | //
7 |
8 | import Foundation
9 |
10 | extension URLRequest {
11 | var curlString: String {
12 | guard let url = url else { return "" }
13 | var baseCommand = "curl \(url.absoluteString)"
14 |
15 | if httpMethod == "HEAD" {
16 | baseCommand += " --head"
17 | }
18 |
19 | var command = [baseCommand]
20 |
21 | if let method = httpMethod, method != "GET" && method != "HEAD" {
22 | command.append("-X \(method)")
23 | }
24 |
25 | if let headers = allHTTPHeaderFields {
26 | for (key, value) in headers where key != "Cookie" {
27 | command.append("-H '\(key): \(value)'")
28 | }
29 | }
30 |
31 | if let data = httpBody,
32 | let body = String(data: data, encoding: .utf8) {
33 | command.append("-d '\(body)'")
34 | }
35 |
36 | return command.joined(separator: " \\\n\t")
37 | }
38 |
39 | init?(curlString: String) {
40 | return nil
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UIImageView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/06.
6 | //
7 |
8 | import UIKit
9 | import Kingfisher
10 |
11 | extension UIImageView {
12 | func setImage(_ kind: ImageAssetKind) {
13 | self.image = kind.image
14 | }
15 |
16 | func setImage(_ kind: ImageAssetKind.Icon) {
17 | self.image = kind.image
18 | }
19 |
20 | func setImage(_ kind: ImageAssetKind.StoreTag) {
21 | self.image = kind.image
22 | }
23 |
24 | func setImage(_ kind: ImageAssetKind.StoreIcon) {
25 | self.image = kind.image
26 | }
27 |
28 | func setImage(_ kind: ImageAssetKind.HeaderView) {
29 | self.image = kind.image
30 | }
31 |
32 | func setImage(_ kind: ImageAssetKind.Splash) {
33 | self.image = kind.image
34 | }
35 |
36 | func setImage(_ kind: ImageAssetKind.Profile) {
37 | self.image = kind.image
38 | }
39 |
40 | func setImage(with url: URL, completion: (() -> Void)? = nil) {
41 | self.kf.setImage(with: url) { _ in
42 | completion?()
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Networking/Config/Config.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Config.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/03.
6 | //
7 |
8 | import Foundation
9 | import Alamofire
10 |
11 | final class Config {
12 |
13 | static var shared = Config()
14 |
15 | private init() {}
16 |
17 | let baseURLString = "https://pyonsnalcolor.store"
18 |
19 | private let defaultHeaders: [HTTPHeader] = [
20 | HTTPHeader(name: "Content-Type", value: "application/json"),
21 | HTTPHeader(name: "Accept", value: "*/*")
22 | ]
23 | }
24 |
25 | extension Config {
26 |
27 | func getDefaultHeader() -> [HTTPHeader]? {
28 | return defaultHeaders
29 | }
30 |
31 | func getAuthorizationHeader(with token: String) -> [HTTPHeader]? {
32 | return [HTTPHeader(name: "Authorization", value: token)] + defaultHeaders
33 | }
34 |
35 | func getMultipartFormDataHeader(id: String? = nil, token: String) -> [HTTPHeader]? {
36 | return [HTTPHeader(name: "Content-Type", value: "multipart/form-data; boundary=\(id ?? "")"),
37 | HTTPHeader(name: "Authorization", value: token)]
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Products/EventProductEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EventProductEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/24.
6 | //
7 |
8 | import Foundation
9 |
10 | struct EventProductEntity: Decodable, ProductConvertable, Hashable {
11 | let productId: String
12 | let imageURL: URL
13 | let storeType: ConvenienceStore
14 | let updatedTime: String
15 | let name: String
16 | let price: String
17 | let originalPrice: String?
18 | let eventType: EventTag?
19 | let productType: ProductType
20 | let description: String?
21 | let isEventExpired: Bool?
22 | let giftItem: String?
23 | let isFavorite: Bool?
24 | let isNew: Bool?
25 |
26 | private enum CodingKeys: String, CodingKey {
27 | case productId = "id"
28 | case imageURL = "image"
29 | case storeType
30 | case updatedTime
31 | case name
32 | case price
33 | case originalPrice = "originPrice"
34 | case eventType
35 | case productType
36 | case description
37 | case isEventExpired
38 | case giftItem = "giftImage"
39 | case isFavorite
40 | case isNew
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_my_selected.imageset/icon_tab_my_selected.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Button/SortButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SortButton.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/22.
6 | //
7 |
8 | import UIKit
9 |
10 | final class SortButton: UIButton {
11 |
12 | enum Size {
13 | static let borderWidth: CGFloat = 1
14 | }
15 |
16 | // MARK: - Initializer
17 | init() {
18 | super.init(frame: .zero)
19 | configureUI()
20 | }
21 |
22 | required init?(coder: NSCoder) {
23 | fatalError("init(coder:) has not been implemented")
24 | }
25 |
26 | // MARK: - Private method
27 | private func configureUI() {
28 | self.isEnabled = false
29 | self.titleLabel?.font = .body3m
30 | self.backgroundColor = .white
31 | self.makeRounded(with: .spacing4)
32 | self.makeBorder(
33 | width: Size.borderWidth,
34 | color: UIColor.gray200.cgColor
35 | )
36 | self.setImage(.sortFilter, for: .normal)
37 | self.setTitleColor(.gray500, for: .normal)
38 | self.contentEdgeInsets = UIEdgeInsets(
39 | top: 0,
40 | left: .spacing6,
41 | bottom: 0,
42 | right: .spacing10
43 | )
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/ImageAssetKind/ImageAssetKind.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAssetKind.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/06/06.
6 | //
7 |
8 | import UIKit
9 |
10 | enum ImageAssetKind: String {
11 | case loginApple = "login_apple"
12 | case loginKakao = "login_kakao"
13 |
14 | case logo = "logo"
15 | case productTag = "product_tag"
16 | case eventTag = "event_tag"
17 | case keywordTag = "keyword_tag"
18 |
19 | case bellSimple = "bellSimple"
20 | case tagStore = "tag_store"
21 |
22 | case iconTitle = "icon_title"
23 |
24 | case event = "event"
25 | case eventSelected = "event.selected"
26 |
27 | case favorite = "icon_like_unselected"
28 | case favoriteSelected = "icon_like_selected"
29 |
30 | /// TermsOfUse
31 | case iconClose = "icon_close"
32 | case iconCloseSmall = "icon_close_small"
33 | case iconDetail = "icon_detail"
34 | case check = "check"
35 | case checkSelected = "check.selected"
36 | case checkSelectedRed = "check.selected.red"
37 | case iconArrow = "icon_arrow"
38 | }
39 |
40 | extension ImageAssetKind {
41 | var image: UIImage? {
42 | return UIImage(named: self.rawValue)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductHome/Views/ReusableView/CurationFooterView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CurationFooterView.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/24.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | final class CurationFooterView: UICollectionReusableView {
12 |
13 | enum Size {
14 | static let footerHeight: CGFloat = 12
15 | }
16 |
17 | private let dividerView: UIView = {
18 | let view = UIView()
19 | view.backgroundColor = .gray100
20 | return view
21 | }()
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: .zero)
25 |
26 | configureLayout()
27 | }
28 |
29 | required init?(coder: NSCoder) {
30 | fatalError("init(coder:) has not been implemented")
31 | }
32 |
33 | private func configureLayout() {
34 | addSubview(dividerView)
35 |
36 | dividerView.snp.makeConstraints { make in
37 | make.leading.trailing.bottom.equalToSuperview()
38 | make.height.equalTo(Size.footerHeight)
39 | }
40 | }
41 |
42 | override func prepareForReuse() {
43 | super.prepareForReuse()
44 |
45 | isHidden = false
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Combine/ControlSubscription.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ControlSubscription.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | final class ControlSubscription: Subscription where ControlSubscriber.Input == ControlPublisher.Output, ControlSubscriber.Failure == ControlPublisher.Failure {
12 | private let selector = #selector(eventHandler)
13 | private var subscriber: ControlSubscriber?
14 | private let control: UIControl
15 | private let controlEvent: UIControl.Event
16 |
17 | init(subscriber: ControlSubscriber, control: UIControl, controlEvent: UIControl.Event) {
18 | self.subscriber = subscriber
19 | self.control = control
20 | self.controlEvent = controlEvent
21 | control.addTarget(self, action: selector, for: controlEvent)
22 | }
23 |
24 | func request(_ demand: Subscribers.Demand) { } // 구현 필요 없음
25 |
26 | func cancel() {
27 | subscriber = nil
28 | control.removeTarget(self, action: selector, for: controlEvent)
29 | }
30 |
31 | @objc
32 | func eventHandler() {
33 | _ = subscriber?.receive(control)
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Button/SelectionButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SelectionButton.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/30.
6 | //
7 |
8 | import UIKit
9 |
10 | final class SelectionButton: UIButton {
11 |
12 | // MARK: - Declaration
13 |
14 | // MARK: - Initializer
15 | init() {
16 | super.init(frame: .zero)
17 |
18 | configureUI()
19 | }
20 |
21 | required init?(coder: NSCoder) {
22 | fatalError("init(coder:) has not been implemented")
23 | }
24 |
25 | // MARK: - Override Method
26 | // override func layoutSubviews() {
27 | // if imageView != nil {
28 | // imageEdgeInsets = .init(top: 0, left: (bounds.width - 35), bottom: 0, right: 5)
29 | // }
30 | // }
31 |
32 | // MARK: - Private Method
33 | private func configureUI() {
34 | contentHorizontalAlignment = .left
35 | semanticContentAttribute = .forceRightToLeft
36 | titleLabel?.font = .body2m
37 | setTitleColor(.red500, for: .selected)
38 | setTitleColor(.gray700, for: .normal)
39 | setImage(ImageAssetKind.Icon.iconCheck.image?.withTintColor(.red500), for: .selected)
40 | setImage(.none, for: .normal)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/NotificationList/NotificationListInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationListInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/27.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol NotificationListRouting: ViewableRouting {
11 | }
12 |
13 | protocol NotificationListPresentable: Presentable {
14 | var listener: NotificationListPresentableListener? { get set }
15 | }
16 |
17 | protocol NotificationListListener: AnyObject {
18 | func notificationListDidTapBackButton()
19 | }
20 |
21 | final class NotificationListInteractor: PresentableInteractor, NotificationListInteractable, NotificationListPresentableListener {
22 |
23 | weak var router: NotificationListRouting?
24 | weak var listener: NotificationListListener?
25 |
26 | override init(presenter: NotificationListPresentable) {
27 | super.init(presenter: presenter)
28 | presenter.listener = self
29 | }
30 |
31 | override func didBecomeActive() {
32 | super.didBecomeActive()
33 | }
34 |
35 | override func willResignActive() {
36 | super.willResignActive()
37 | }
38 |
39 | func didTabBackButton() {
40 | listener?.notificationListDidTapBackButton()
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UICollectionView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionView+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/23.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UICollectionView {
11 | func register(_ viewClass: AnyClass) {
12 | register(viewClass, forCellWithReuseIdentifier: String(describing: viewClass.self))
13 | }
14 |
15 | func registerHeaderView(_ viewClass: AnyClass) {
16 | register(
17 | viewClass,
18 | forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
19 | withReuseIdentifier: String(describing: viewClass.self)
20 | )
21 | }
22 |
23 | func registerFooterView(_ viewClass: AnyClass) {
24 | register(
25 | viewClass,
26 | forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
27 | withReuseIdentifier: String(describing: viewClass.self)
28 | )
29 | }
30 |
31 | func dequeueReusableCell(for indexPath: IndexPath) -> T {
32 | guard let cell = self.dequeueReusableCell(withReuseIdentifier: T.identifier, for: indexPath) as? T else {
33 | fatalError("Unexpected identifier : \(T.identifier)")
34 | }
35 | return cell
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/TermsOfUse/TermsOfUseBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermsOfUseBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/06.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol TermsOfUseDependency: Dependency {
11 |
12 | }
13 |
14 | final class TermsOfUseComponent: Component,
15 | CommonWebDependency {
16 |
17 | }
18 |
19 | // MARK: - Builder
20 |
21 | protocol TermsOfUseBuildable: Buildable {
22 | func build(withListener listener: TermsOfUseListener) -> TermsOfUseRouting
23 | }
24 |
25 | final class TermsOfUseBuilder: Builder, TermsOfUseBuildable {
26 |
27 |
28 | override init(dependency: TermsOfUseDependency) {
29 | super.init(dependency: dependency)
30 | }
31 |
32 | func build(withListener listener: TermsOfUseListener) -> TermsOfUseRouting {
33 | let component = TermsOfUseComponent(dependency: dependency)
34 | let viewController = TermsOfUseViewController()
35 | let commonWebBuilder = CommonWebBuilder(dependency: component)
36 | let interactor = TermsOfUseInteractor(presenter: viewController)
37 | interactor.listener = listener
38 | return TermsOfUseRouter(interactor: interactor, viewController: viewController, commonWebBuilder: commonWebBuilder)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoginPopup/LoginPopupBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginPopupBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/31/24.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LoginPopupDependency: Dependency {
11 | // TODO: Declare the set of dependencies required by this RIB, but cannot be
12 | // created by this RIB.
13 | }
14 |
15 | final class LoginPopupComponent: Component {
16 |
17 | // TODO: Declare 'fileprivate' dependencies that are only used by this RIB.
18 | }
19 |
20 | // MARK: - Builder
21 |
22 | protocol LoginPopupBuildable: Buildable {
23 | func build(withListener listener: LoginPopupListener) -> LoginPopupRouting
24 | }
25 |
26 | final class LoginPopupBuilder: Builder, LoginPopupBuildable {
27 |
28 | override init(dependency: LoginPopupDependency) {
29 | super.init(dependency: dependency)
30 | }
31 |
32 | func build(withListener listener: LoginPopupListener) -> LoginPopupRouting {
33 | let component = LoginPopupComponent(dependency: dependency)
34 | let viewController = LoginPopupViewController()
35 | let interactor = LoginPopupInteractor(presenter: viewController)
36 | interactor.listener = listener
37 | return LoginPopupRouter(interactor: interactor, viewController: viewController)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoginPopup/LoginPopupInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginPopupInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/31/24.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LoginPopupRouting: ViewableRouting {
11 | }
12 |
13 | protocol LoginPopupPresentable: Presentable {
14 | var listener: LoginPopupPresentableListener? { get set }
15 | }
16 |
17 | protocol LoginPopupListener: AnyObject {
18 | func popupDidTapDismiss()
19 | func popupDidTapConfirm()
20 | }
21 |
22 | final class LoginPopupInteractor: PresentableInteractor,
23 | LoginPopupInteractable,
24 | LoginPopupPresentableListener {
25 |
26 | weak var router: LoginPopupRouting?
27 | weak var listener: LoginPopupListener?
28 |
29 | override init(presenter: LoginPopupPresentable) {
30 | super.init(presenter: presenter)
31 | presenter.listener = self
32 | }
33 |
34 | override func didBecomeActive() {
35 | super.didBecomeActive()
36 | }
37 |
38 | override func willResignActive() {
39 | super.willResignActive()
40 | }
41 |
42 | func popupDidTapDismiss() {
43 | listener?.popupDidTapDismiss()
44 | }
45 |
46 | func popupDidTapConfirm() {
47 | listener?.popupDidTapConfirm()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Service/UserAuthService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserAuthService.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/08.
6 | //
7 |
8 | final class UserAuthService {
9 |
10 | // MARK: - Private Property
11 | private let accessTokenKey: String = "UserAuthService.AccessToken.Key"
12 | private let refreshTokenKey: String = "UserAuthService.RefreshToken.Key"
13 | private let keyChainService: KeyChainService
14 |
15 | // MARK: - Initializer
16 | init(keyChainService: KeyChainService) {
17 | self.keyChainService = keyChainService
18 | }
19 |
20 | // MARK: - Interface
21 | func getAccessToken() -> String? {
22 | keyChainService.get(with: accessTokenKey)
23 | }
24 |
25 | func getRefreshToken() -> String? {
26 | keyChainService.get(with: refreshTokenKey)
27 | }
28 |
29 | func setAccessToken(_ token: String) {
30 | _ = keyChainService.set(value: token, to: accessTokenKey)
31 | }
32 |
33 | func setRefreshToken(_ token: String) {
34 | _ = keyChainService.set(value: token, to: refreshTokenKey)
35 | }
36 |
37 | func deleteAccessToken() {
38 | keyChainService.delete(with: accessTokenKey)
39 | }
40 |
41 | func deleteRefreshToken() {
42 | keyChainService.delete(with: refreshTokenKey)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/RootTabBar/RootTabBarInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootTabBarInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/10.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol RootTabBarRouting: ViewableRouting {
11 | func attachTabs()
12 | }
13 |
14 | protocol RootTabBarPresentable: Presentable {
15 | var listener: RootTabBarPresentableListener? { get set }
16 | }
17 |
18 | protocol RootTabBarListener: AnyObject {
19 | func routeToLoggedOut()
20 | func routeToLoggedIn()
21 | }
22 |
23 | final class RootTabBarInteractor:
24 | PresentableInteractor,
25 | RootTabBarInteractable,
26 | RootTabBarPresentableListener {
27 |
28 | weak var router: RootTabBarRouting?
29 | weak var listener: RootTabBarListener?
30 |
31 | override init(presenter: RootTabBarPresentable) {
32 | super.init(presenter: presenter)
33 | presenter.listener = self
34 | }
35 |
36 | override func didBecomeActive() {
37 | super.didBecomeActive()
38 |
39 | router?.attachTabs()
40 | }
41 |
42 | override func willResignActive() {
43 | super.willResignActive()
44 | }
45 |
46 | func routeToLoggedOut() {
47 | listener?.routeToLoggedOut()
48 | }
49 |
50 | func routeToLoggedIn() {
51 | listener?.routeToLoggedIn()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/UIView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/14.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | /// 둥글게 만들어줍니다.
12 | /// - Parameter cornerRadius: 곡선 값
13 | func makeRounded(with cornerRadius: CGFloat) {
14 | self.layer.cornerRadius = cornerRadius
15 | self.layer.masksToBounds = true
16 | }
17 |
18 | /// 특정 모서리만 둥글게 만들어 줍니다.
19 | /// - Parameter cornerRadius: 곡선 값
20 | /// - Parameter maskedCorners: 적용할 corners
21 | func makeRoundCorners(cornerRadius: CGFloat, maskedCorners: CACornerMask) {
22 | self.clipsToBounds = true
23 | self.layer.cornerRadius = cornerRadius
24 | self.layer.maskedCorners = CACornerMask(arrayLiteral: maskedCorners)
25 | }
26 |
27 | func makeBorder(width: CGFloat, color: CGColor) {
28 | self.layer.borderWidth = width
29 | self.layer.borderColor = color
30 | }
31 |
32 | func removeBorder() {
33 | self.layer.borderWidth = 0
34 | }
35 |
36 | func addTapGesture(tapNumber: Int = 1, target: AnyObject, action: Selector) {
37 | let tap = UITapGestureRecognizer(target: target, action: action)
38 | tap.numberOfTapsRequired = tapNumber
39 | addGestureRecognizer(tap)
40 | isUserInteractionEnabled = true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductHome/Views/Cell/CurationImageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CurationImageCell.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/24.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 | import Lottie
11 |
12 | final class CurationImageCell: UICollectionViewCell {
13 |
14 | let containerView: UIView = {
15 | let view = UIView()
16 | return view
17 | }()
18 |
19 | private let introductionImageView: LottieAnimationView = {
20 | let animation = LottieAnimation.named("main")
21 | let animationView = LottieAnimationView(animation: animation)
22 | animationView.contentMode = .scaleAspectFill
23 | animationView.loopMode = .loop
24 | animationView.play()
25 | return animationView
26 | }()
27 |
28 | override init(frame: CGRect) {
29 | super.init(frame: frame)
30 |
31 | configureLayout()
32 | }
33 |
34 | required init?(coder: NSCoder) {
35 | fatalError("init(coder:) has not been implemented")
36 | }
37 |
38 | private func configureLayout() {
39 | addSubview(containerView)
40 | containerView.addSubview(introductionImageView)
41 |
42 | containerView.snp.makeConstraints {
43 | $0.edges.equalToSuperview()
44 | }
45 | introductionImageView.frame = self.bounds
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Root/RootComponent.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootComponent.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/10.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol RootDependencyLoggedOut: Dependency {
11 | }
12 |
13 | final class RootComponent: Component {
14 |
15 | let rootViewController: RootViewController
16 | var appleLoginService: AppleLoginService
17 | var kakaoLoginService: KakaoLoginService
18 | let userAuthService: UserAuthService
19 | var authClient: AuthAPIService
20 |
21 | init(rootViewController: RootViewController,
22 | dependency: RootDependency
23 | ) {
24 | self.rootViewController = rootViewController
25 | self.appleLoginService = AppleLoginService()
26 | self.kakaoLoginService = KakaoLoginService()
27 | let keyChainService = KeyChainService.shared
28 | self.userAuthService = .init(keyChainService: keyChainService)
29 | let pyonsnalColorClient = PyonsnalColorClient()
30 | self.authClient = .init(client: pyonsnalColorClient)
31 | super.init(dependency: dependency)
32 | }
33 | }
34 |
35 | extension RootComponent: LoggedOutDependency {
36 | }
37 |
38 | extension RootComponent: LoggedInDependency {
39 |
40 | var loggedInViewController: LoggedInViewControllable {
41 | return rootViewController
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Root/RootBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/05/29.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol RootDependency: Dependency {
11 | var userAuthService: UserAuthService { get }
12 | }
13 |
14 | // MARK: - Builder
15 |
16 | protocol RootBuildable: Buildable {
17 | func build() -> LaunchRouting
18 | }
19 |
20 | final class RootBuilder: Builder, RootBuildable {
21 |
22 | override init(dependency: RootDependency) {
23 | super.init(dependency: dependency)
24 | }
25 |
26 | func build() -> LaunchRouting {
27 | let viewController = RootViewController()
28 | let component: RootComponent = .init(
29 | rootViewController: viewController,
30 | dependency: dependency
31 | )
32 | let interactor: RootInteractor = .init(presenter: viewController, dependency: dependency)
33 | let loggedOutBuilder: LoggedOutBuilder = .init(dependency: component)
34 | let loggedInBuilder: LoggedInBuilder = .init(dependency: component)
35 | let router: RootRouter = .init(
36 | interactor: interactor,
37 | viewController: viewController,
38 | loggedOutBuilder: loggedOutBuilder,
39 | loggedInBuilder: loggedInBuilder
40 | )
41 |
42 | return router
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ImageCell/ProductDetailImageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailImageCell.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/10.
6 | //
7 |
8 | import UIKit
9 |
10 | final class ProductDetailImageCell: UICollectionViewCell {
11 |
12 | // MARK: - Declaration
13 | struct Payload {
14 | let imageURL: URL
15 | }
16 |
17 | // MARK: - Interface
18 | var payload: Payload? {
19 | didSet { configure() }
20 | }
21 |
22 | // MARK: - Private Property
23 | private let viewHolder: ViewHolder = .init()
24 |
25 | // MARK: - Initializer
26 | override init(frame: CGRect) {
27 | super.init(frame: .zero)
28 |
29 | configureView()
30 | configureConstraint()
31 | }
32 |
33 | required init?(coder: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 |
37 | // MARK: - Private Method
38 | private func configureView() {
39 | viewHolder.place(in: contentView)
40 | }
41 |
42 | private func configureConstraint() {
43 | viewHolder.configureConstraints(for: contentView)
44 | }
45 |
46 | private func configure() {
47 | guard let payload else {
48 | return
49 | }
50 | viewHolder.imageView.setImage(with: payload.imageURL)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Service/KakaoLoginService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KakaoLoginService.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/06.
6 | //
7 |
8 | import Foundation
9 | import KakaoSDKUser
10 |
11 | protocol KakaoLoginServiceDelegate: AnyObject {
12 | func didReceive(accessToken: String)
13 | }
14 |
15 | final class KakaoLoginService: NSObject {
16 |
17 | weak var delegate: KakaoLoginServiceDelegate?
18 |
19 | func requestKakaoLogin() {
20 | if UserApi.isKakaoTalkLoginAvailable() {
21 | UserApi.shared.loginWithKakaoTalk { [weak self] (oauthToken, error) in
22 | if let error = error {
23 | print(error)
24 | } else {
25 | if let accessToken = oauthToken?.accessToken {
26 | self?.delegate?.didReceive(accessToken: accessToken)
27 | }
28 | }
29 | }
30 | } else {
31 | UserApi.shared.loginWithKakaoAccount { [weak self] (oauthToken, error) in
32 | if let error = error {
33 | print(error)
34 | } else {
35 | if let accessToken = oauthToken?.accessToken {
36 | self?.delegate?.didReceive(accessToken: accessToken)
37 | }
38 | }
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Networking/Auth/AuthAPIService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthAPIService.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/08.
6 | //
7 |
8 | final class AuthAPIService {
9 |
10 | // MARK: - Private Property
11 | private let client: PyonsnalColorClient
12 |
13 | // MARK: - Initializer
14 | init(client: PyonsnalColorClient) {
15 | self.client = client
16 | }
17 |
18 | // MARK: - Interface
19 | func login(token: String, authType: AuthType) -> ResponsePublisher {
20 | return client.request(
21 | AuthRouter.login(token: token, authType: authType),
22 | model: UserAuthEntity.self
23 | )
24 | }
25 |
26 | func guestLogin() -> ResponsePublisher {
27 | return client.request(AuthRouter.guestLogin, model: UserAuthEntity.self)
28 | }
29 |
30 | func loginStatus(token: String, authType: AuthType) -> ResponsePublisher {
31 | return client.request(
32 | AuthRouter.loginStatus(token: token, authType: authType),
33 | model: UserLoginStatusEntity.self
34 | )
35 | }
36 |
37 | func reissue(userAuth: UserAuthEntity) -> ResponsePublisher {
38 | return client.request(
39 | AuthRouter.reissue(userAuth: userAuth),
40 | model: UserAuthEntity.self
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/TabBar/icon_tab_sale_unselected.imageset/icon_tab_sale_unselected.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/NotificationList/NotificationListBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationListBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/27.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol NotificationListDependency: Dependency {
11 | // TODO: Declare the set of dependencies required by this RIB, but cannot be
12 | // created by this RIB.
13 | }
14 |
15 | final class NotificationListComponent: Component {
16 |
17 | // TODO: Declare 'fileprivate' dependencies that are only used by this RIB.
18 | }
19 |
20 | // MARK: - Builder
21 |
22 | protocol NotificationListBuildable: Buildable {
23 | func build(withListener listener: NotificationListListener) -> NotificationListRouting
24 | }
25 |
26 | final class NotificationListBuilder: Builder, NotificationListBuildable {
27 |
28 | override init(dependency: NotificationListDependency) {
29 | super.init(dependency: dependency)
30 | }
31 |
32 | func build(withListener listener: NotificationListListener) -> NotificationListRouting {
33 | let component = NotificationListComponent(dependency: dependency)
34 | let viewController = NotificationListViewController()
35 | let interactor = NotificationListInteractor(presenter: viewController)
36 | interactor.listener = listener
37 | return NotificationListRouter(interactor: interactor, viewController: viewController)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Combine/GestureSubscription.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GestureSubscription.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/09/06.
6 | //
7 |
8 | import UIKit
9 | import Combine
10 |
11 | final class GestureSubscription: Subscription where GestureSubscriber.Input == GesturePublisher.Output, GestureSubscriber.Failure == GesturePublisher.Failure {
12 | private let selector = #selector(gestureHandler)
13 | private var subscriber: GestureSubscriber?
14 | private weak var targetView: UIView?
15 | private let gestureRecognizer: UIGestureRecognizer
16 |
17 | init(subscriber: GestureSubscriber?, view: UIView?, gestureRecognizer: UIGestureRecognizer) {
18 | self.subscriber = subscriber
19 | self.targetView = view
20 | self.gestureRecognizer = gestureRecognizer
21 |
22 | self.targetView?.isUserInteractionEnabled = true
23 | gestureRecognizer.addTarget(self, action: selector)
24 | self.targetView?.addGestureRecognizer(gestureRecognizer)
25 | }
26 |
27 | func request(_ demand: Subscribers.Demand) { } // 구현 필요 없음
28 |
29 | func cancel() {
30 | subscriber = nil
31 | targetView?.isUserInteractionEnabled = false
32 | gestureRecognizer.removeTarget(self, action: selector)
33 | }
34 |
35 | @objc
36 | private func gestureHandler() {
37 | _ = subscriber?.receive(gestureRecognizer)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoggedIn/LoggedInBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoggedInBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/06/10.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol LoggedInDependency: Dependency {
11 | var loggedInViewController: LoggedInViewControllable { get }
12 | }
13 |
14 | final class LoggedInComponent: Component, RootTabBarDependency {
15 | fileprivate var loggedInViewController: LoggedInViewControllable {
16 | return dependency.loggedInViewController
17 | }
18 | }
19 |
20 | // MARK: - Builder
21 |
22 | protocol LoggedInBuildable: Buildable {
23 | func build(withListener listener: LoggedInListener) -> LoggedInRouting
24 | }
25 |
26 | final class LoggedInBuilder: Builder, LoggedInBuildable {
27 |
28 | override init(dependency: LoggedInDependency) {
29 | super.init(dependency: dependency)
30 | }
31 |
32 | func build(withListener listener: LoggedInListener) -> LoggedInRouting {
33 | let component = LoggedInComponent(dependency: dependency)
34 | let interactor = LoggedInInteractor()
35 | let rootTabBarBuilder = RootTabBarBuilder(dependency: component)
36 | interactor.listener = listener
37 | let router = LoggedInRouter(
38 | interactor: interactor,
39 | viewController: component.loggedInViewController,
40 | rootTabBarBuilder: rootTabBarBuilder
41 | )
42 |
43 | return router
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/TermsOfUse/View/TermsButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermsButton.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/06.
6 | //
7 |
8 | import UIKit
9 |
10 | final class TermsButton: UIButton {
11 |
12 | // MARK: - Initializer
13 | init(
14 | textColor: UIColor,
15 | font: UIFont,
16 | isSelected: Bool
17 | ) {
18 | super.init(frame: .zero)
19 | configureUI(textColor: textColor,
20 | font: font)
21 | }
22 |
23 | required init?(coder: NSCoder) {
24 | fatalError("init(coder:) has not been implemented")
25 | }
26 |
27 | // MARK: - Method
28 | func setButtonState(isSelected: Bool) {
29 | self.isSelected = isSelected
30 | }
31 |
32 | func isCurrentSelected() -> Bool {
33 | return isSelected
34 | }
35 |
36 | // MARK: - Private method
37 | private func configureUI(textColor: UIColor,
38 | font: UIFont) {
39 | self.titleLabel?.font = font
40 | self.setTitleColor(textColor, for: .normal)
41 | self.setImage(.check, for: .normal)
42 | self.setImage(.checkSelected, for: .selected)
43 | self.contentHorizontalAlignment = .left
44 | self.titleEdgeInsets = UIEdgeInsets(top: 0,
45 | left: .spacing8,
46 | bottom: 0,
47 | right: 0)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/LoginPopup/LoginPopupViewHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginPopupViewHolder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 1/31/24.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | extension LoginPopupViewController {
12 | final class ViewHolder: ViewHolderable {
13 |
14 | enum Constant {
15 | static let popupHeight: CGFloat = 208
16 |
17 | static let backgroundColor: UIColor = .black.withAlphaComponent(0.4)
18 | }
19 |
20 | private let backgroundView: UIView = {
21 | let view = UIView()
22 | view.backgroundColor = Constant.backgroundColor
23 | return view
24 | }()
25 |
26 | let popupView = PopupView(state: .normal)
27 |
28 | func place(in view: UIView) {
29 | view.addSubview(backgroundView)
30 |
31 | backgroundView.addSubview(popupView)
32 | }
33 |
34 | func configureConstraints(for view: UIView) {
35 | backgroundView.snp.makeConstraints {
36 | $0.edges.equalTo(view)
37 | }
38 |
39 | popupView.snp.makeConstraints {
40 | $0.leading.equalToSuperview().offset(.spacing16)
41 | $0.trailing.equalToSuperview().inset(.spacing16)
42 | $0.centerY.equalToSuperview()
43 | $0.height.equalTo(Constant.popupHeight)
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Filter/FilterEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FilterEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/22.
6 | //
7 |
8 | import UIKit
9 |
10 | struct FilterDataEntity: Decodable, Hashable {
11 | var data: [FilterEntity]
12 | }
13 |
14 | struct FilterEntity: Decodable {
15 | let filterType: FilterType
16 | var defaultText: String? // 카테고리에 보여질 이름
17 | var isSelected: Bool = false
18 | var filterItem: [FilterItemEntity]
19 |
20 | enum CodingKeys: String, CodingKey {
21 | case filterType, filterItem
22 | }
23 |
24 | init(filterType: FilterType, defaultText: String?, filterItem: [FilterItemEntity]) {
25 | self.filterType = filterType
26 | self.defaultText = defaultText
27 | self.filterItem = filterItem
28 | }
29 | }
30 |
31 | extension FilterEntity: Hashable {
32 | static func == (lhs: FilterEntity, rhs: FilterEntity) -> Bool {
33 | return lhs.filterItem == rhs.filterItem
34 | }
35 |
36 | func hash(into hasher: inout Hasher) {
37 | hasher.combine(filterItem)
38 | }
39 | }
40 |
41 | struct FilterItemEntity: Decodable, Hashable {
42 | let name: String
43 | let code: Int
44 | let image: String?
45 |
46 | var isSelected = false
47 |
48 | enum CodingKeys: String, CodingKey {
49 | case name, code, image
50 | }
51 |
52 | func hash(into hasher: inout Hasher) {
53 | hasher.combine(name)
54 | hasher.combine(code)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Service/UserInfoService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserInfoService.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/10/25.
6 | //
7 |
8 | import Combine
9 | import AdSupport
10 |
11 | final class UserInfoService {
12 |
13 | static let shared = UserInfoService()
14 |
15 | // MARK: - Private Property
16 |
17 | private var memberInfo: MemberInfoEntity?
18 | private var cancellable = Set()
19 |
20 | private let client = PyonsnalColorClient()
21 | private let userAuthService = UserAuthService(keyChainService: .shared)
22 | private lazy var memberAPIService = MemberAPIService(client: client, userAuthService: userAuthService)
23 |
24 | var memberID: Int? {
25 | return memberInfo?.memberId
26 | }
27 | var adId: String {
28 | ASIdentifierManager.shared().advertisingIdentifier.uuidString
29 | }
30 | var isGuest: Bool? {
31 | return memberInfo?.isGuest
32 | }
33 |
34 | // MARK: - Initializer
35 |
36 | private init() {}
37 |
38 | // MARK: - Private Method
39 |
40 | func configure() {
41 | requestMemberInfo()
42 | }
43 |
44 | private func requestMemberInfo() {
45 | memberAPIService.info()
46 | .sink { [weak self] response in
47 | if let memberInfo = response.value {
48 | self?.memberInfo = memberInfo
49 | }
50 | }
51 | .store(in: &cancellable)
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ReviewPopup/ReviewPopupInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewPopupInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/09/21.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ReviewPopupRouting: ViewableRouting {
11 | }
12 |
13 | protocol ReviewPopupPresentable: Presentable {
14 | var listener: ReviewPopupPresentableListener? { get set }
15 | }
16 |
17 | protocol ReviewPopupListener: AnyObject {
18 | func popupDidTapDismissButton()
19 | func popupDidTapBackButton()
20 | func routeToProductDetail()
21 | }
22 |
23 | final class ReviewPopupInteractor: PresentableInteractor,
24 | ReviewPopupInteractable,
25 | ReviewPopupPresentableListener {
26 |
27 | weak var router: ReviewPopupRouting?
28 | weak var listener: ReviewPopupListener?
29 |
30 | override init(presenter: ReviewPopupPresentable) {
31 | super.init(presenter: presenter)
32 | presenter.listener = self
33 | }
34 |
35 | override func didBecomeActive() {
36 | super.didBecomeActive()
37 | }
38 |
39 | override func willResignActive() {
40 | super.willResignActive()
41 | }
42 |
43 | func didTapApplyButton() {
44 | listener?.routeToProductDetail()
45 | }
46 |
47 | func didTapDismissButton() {
48 | listener?.popupDidTapDismissButton()
49 | }
50 |
51 | func didTapBackButton() {
52 | listener?.popupDidTapBackButton()
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Curation/HomeBannerEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeBannerEntity.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 12/26/23.
6 | //
7 |
8 | import Foundation
9 |
10 | struct HomeBanner: Decodable {
11 | let homeBanner: [HomeBannerEntity]
12 | }
13 |
14 | struct HomeBannerEntity: Decodable {
15 | let type: String
16 | let value: [HomeBannerValue]
17 | }
18 |
19 | struct HomeBannerValue: Decodable {
20 | let curationProducts: CurationEntity?
21 | let eventBanners: EventImageEntity?
22 |
23 | enum CodingKeys: CodingKey {
24 | case curationProducts
25 | case eventBanners
26 | }
27 |
28 | init(curationProducts: CurationEntity? = nil, eventBanners: EventImageEntity? = nil) {
29 | self.curationProducts = curationProducts
30 | self.eventBanners = eventBanners
31 | }
32 |
33 | init(from decoder: Decoder) throws {
34 | let container = try decoder.singleValueContainer()
35 |
36 | if let value = try? container.decode(CurationEntity.self) {
37 | self = .init(curationProducts: value)
38 | return
39 | }
40 |
41 | if let value = try? container.decode(EventImageEntity.self) {
42 | self = .init(eventBanners: value)
43 | return
44 | }
45 |
46 | throw DecodingError.typeMismatch(
47 | HomeBannerValue.self,
48 | .init(codingPath: decoder.codingPath, debugDescription: "Type Mismatch")
49 | )
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_filled_large.imageset/filled=filled, size=L.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/star_filled_medium.imageset/filled=filled, size=m.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color.xcodeproj/xcuserdata/gamza.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Promises (Playground) 1.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 2
13 |
14 | Promises (Playground) 2.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 3
20 |
21 | Promises (Playground).xcscheme
22 |
23 | isShown
24 |
25 | orderHint
26 | 0
27 |
28 | Pyonsnal-Color.xcscheme_^#shared#^_
29 |
30 | orderHint
31 | 0
32 |
33 | SnapKitPlayground (Playground) 1.xcscheme
34 |
35 | isShown
36 |
37 | orderHint
38 | 2
39 |
40 | SnapKitPlayground (Playground) 2.xcscheme
41 |
42 | isShown
43 |
44 | orderHint
45 | 3
46 |
47 | SnapKitPlayground (Playground).xcscheme
48 |
49 | isShown
50 |
51 | orderHint
52 | 0
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/Cell/EmptyCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyCell.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/24.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | final class EmptyCell: UICollectionViewCell {
12 |
13 | // MARK: - Declaration
14 | enum Text {
15 | enum Search {
16 | static let titleLabelText = "앗! 원하는 검색 결과가 없어요."
17 | static let subtitleLabelText = "단어의 철자가 올바른지 한 번 더 확인해주세요."
18 | }
19 |
20 | enum Favorite {
21 | static let titleLabelText = "찜한 상품이 없습니다."
22 | static let subTitleLableText = "마음에 드는 상품의 하트를 눌러 저장해 보세요."
23 | }
24 | }
25 |
26 | // MARK: - Private Property
27 | private let viewHolder: ViewHolder = .init()
28 |
29 | // MARK: - Initializer
30 | override init(frame: CGRect) {
31 | super.init(frame: .zero)
32 |
33 | configureView()
34 | configureConstraint()
35 | }
36 |
37 | required init?(coder: NSCoder) {
38 | fatalError("init(coder:) has not been implemented")
39 | }
40 |
41 | func setText(titleText: String, subTitleText: String) {
42 | viewHolder.titleLabel.text = titleText
43 | viewHolder.subtitleLabel.text = subTitleText
44 | }
45 |
46 | // MARK: - Private Method
47 | private func configureView() {
48 | viewHolder.place(in: contentView)
49 | }
50 |
51 | private func configureConstraint() {
52 | viewHolder.configureConstraints(for: contentView)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductFilter/ProductFilterBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductFilterBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/25.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProductFilterDependency: Dependency {
11 | // TODO: Declare the set of dependencies required by this RIB, but cannot be
12 | // created by this RIB.
13 | }
14 |
15 | final class ProductFilterComponent: Component {
16 |
17 | // TODO: Declare 'fileprivate' dependencies that are only used by this RIB.
18 | }
19 |
20 | // MARK: - Builder
21 |
22 | protocol ProductFilterBuildable: Buildable {
23 | func build(
24 | withListener listener: ProductFilterListener,
25 | filterEntity: FilterEntity
26 | ) -> ProductFilterRouting
27 | }
28 |
29 | final class ProductFilterBuilder: Builder, ProductFilterBuildable {
30 |
31 | override init(dependency: ProductFilterDependency) {
32 | super.init(dependency: dependency)
33 | }
34 |
35 | func build(
36 | withListener listener: ProductFilterListener,
37 | filterEntity: FilterEntity
38 | ) -> ProductFilterRouting {
39 | let component = ProductFilterComponent(dependency: dependency)
40 | let viewController = ProductFilterViewController(filterEntity: filterEntity)
41 | let interactor = ProductFilterInteractor(presenter: viewController)
42 | interactor.listener = listener
43 | return ProductFilterRouter(interactor: interactor, viewController: viewController)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProfileEdit/ProfileEditBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileEditBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 11/16/23.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProfileEditDependency: Dependency {
11 | var memberAPIService: MemberAPIService { get }
12 | }
13 |
14 | final class ProfileEditComponent: Component {
15 | var memberInfo: MemberInfoEntity
16 | init(dependency: ProfileEditDependency, memberInfo: MemberInfoEntity) {
17 | self.memberInfo = memberInfo
18 | super.init(dependency: dependency)
19 | }
20 | }
21 |
22 | // MARK: - Builder
23 |
24 | protocol ProfileEditBuildable: Buildable {
25 | func build(withListener listener: ProfileEditListener, memberInfo: MemberInfoEntity) -> ProfileEditRouting
26 | }
27 |
28 | final class ProfileEditBuilder: Builder, ProfileEditBuildable {
29 |
30 | override init(dependency: ProfileEditDependency) {
31 | super.init(dependency: dependency)
32 | }
33 |
34 | func build(
35 | withListener listener: ProfileEditListener,
36 | memberInfo: MemberInfoEntity
37 | ) -> ProfileEditRouting {
38 | let component = ProfileEditComponent(dependency: dependency, memberInfo: memberInfo)
39 | let viewController = ProfileEditViewController()
40 | let interactor = ProfileEditInteractor(presenter: viewController, component: component)
41 | interactor.listener = listener
42 | return ProfileEditRouter(interactor: interactor, viewController: viewController)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Resource/Assets.xcassets/Review/icon_review.imageset/icon_review.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/BottomSheet/BottomSheetDismissAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomSheetDismissAnimator.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/07/30.
6 | //
7 |
8 | import UIKit
9 |
10 | class BottomSheetDismissAnimator: NSObject {
11 | let animateDuration: CGFloat
12 |
13 | required init(with duration: CGFloat = 0.2) {
14 | self.animateDuration = duration
15 | }
16 | }
17 |
18 | extension BottomSheetDismissAnimator: UIViewControllerAnimatedTransitioning {
19 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
20 | animateDuration
21 | }
22 |
23 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
24 | // fromViewController is presented view controller
25 | guard let fromViewController = transitionContext.viewController(forKey: .from) else { return }
26 |
27 | let containerView = transitionContext.containerView
28 | let estimatedHeight = transitionContext.finalFrame(for: fromViewController).height
29 |
30 | UIView.animate(
31 | withDuration: animateDuration,
32 | delay: 0.0,
33 | options: .curveEaseIn,
34 | animations: {
35 | containerView.alpha = 0.0
36 | fromViewController.view.transform = CGAffineTransform(translationX: 0.0, y: estimatedHeight / 2.0)
37 | },
38 | completion: { _ in
39 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
40 | })
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductFilter/ProductFilterInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductFilterInteractor.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김인호 on 2023/07/25.
6 | //
7 |
8 | import ModernRIBs
9 |
10 | protocol ProductFilterRouting: ViewableRouting {
11 | }
12 |
13 | protocol ProductFilterPresentable: Presentable {
14 | var listener: ProductFilterPresentableListener? { get set }
15 | }
16 |
17 | protocol ProductFilterListener: AnyObject {
18 | func applyFilterItems(_ items: [FilterItemEntity], type: FilterType)
19 | func applySortFilter(item: FilterItemEntity)
20 | func productFilterDidTapCloseButton()
21 | }
22 |
23 | final class ProductFilterInteractor: PresentableInteractor, ProductFilterInteractable, ProductFilterPresentableListener {
24 |
25 | weak var router: ProductFilterRouting?
26 | weak var listener: ProductFilterListener?
27 |
28 | override init(presenter: ProductFilterPresentable) {
29 | super.init(presenter: presenter)
30 | presenter.listener = self
31 | }
32 |
33 | override func didBecomeActive() {
34 | super.didBecomeActive()
35 | }
36 |
37 | override func willResignActive() {
38 | super.willResignActive()
39 | }
40 |
41 | func didTapApplyButton(with selectedItems: [FilterItemEntity], type: FilterType) {
42 | listener?.applyFilterItems(selectedItems, type: type)
43 | }
44 |
45 | func didSelectSortFilter(item: FilterItemEntity) {
46 | listener?.applySortFilter(item: item)
47 | }
48 |
49 | func didTapCloseButton() {
50 | listener?.productFilterDidTapCloseButton()
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Common/ReusableView/ItemHeaderTitleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemHeaderTitleView.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/10.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | final class ItemHeaderTitleView: UICollectionReusableView {
12 |
13 | enum Size {
14 | static let labelGreaterThanEqualLeading: CGFloat = 100
15 | }
16 |
17 | // MARK: - Private property
18 | private let viewHolder: ViewHolder = .init()
19 |
20 | // MARK: - Initializer
21 | override init(frame: CGRect) {
22 | super.init(frame: .zero)
23 | viewHolder.place(in: self)
24 | viewHolder.configureConstraints(for: self)
25 | }
26 |
27 | required init?(coder: NSCoder) {
28 | fatalError("init(coder:) has not been implemented")
29 | }
30 |
31 | func update(title: String) {
32 | viewHolder.titleLabel.text = title
33 | }
34 | }
35 |
36 | extension ItemHeaderTitleView {
37 | class ViewHolder: ViewHolderable {
38 |
39 | let titleLabel: UILabel = {
40 | let label = UILabel()
41 | label.font = .body2m
42 | return label
43 | }()
44 |
45 | func place(in view: UIView) {
46 | view.addSubview(titleLabel)
47 | }
48 |
49 | func configureConstraints(for view: UIView) {
50 | titleLabel.snp.makeConstraints {
51 | $0.leading.equalToSuperview().offset(.spacing16)
52 | $0.top.equalToSuperview().offset(.spacing24)
53 | $0.bottom.equalToSuperview()
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Entity/Review/ReviewEvaluationKind.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReviewEvaluationKind.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/29.
6 | //
7 |
8 | enum ReviewEvaluationKind {
9 | case taste
10 | case quality
11 | case valueForMoney
12 |
13 | var name: String {
14 | switch self {
15 | case .taste:
16 | return "맛"
17 | case .quality:
18 | return "퀄리티"
19 | case .valueForMoney:
20 | return "가격"
21 | }
22 | }
23 |
24 | var detailReviewTitle: String {
25 | switch self {
26 | case .taste:
27 | return "상품의 맛은 어떤가요?"
28 | case .quality:
29 | return "상품의 퀄리티는 어떤가요?"
30 | case .valueForMoney:
31 | return "상품의 가격은 어떤가요?"
32 | }
33 | }
34 |
35 | var goodStateText: String {
36 | switch self {
37 | case .taste:
38 | return "맛있어요"
39 | case .quality:
40 | return "좋아요"
41 | case .valueForMoney:
42 | return "합리적이에요"
43 | }
44 | }
45 |
46 | var normalStateText: String {
47 | switch self {
48 | case .taste:
49 | return "보통이에요"
50 | case .quality:
51 | return "보통이에요"
52 | case .valueForMoney:
53 | return "적당해요"
54 | }
55 | }
56 |
57 | var badStateText: String {
58 | switch self {
59 | case .taste:
60 | return "별로에요"
61 | case .quality:
62 | return "별로에요"
63 | case .valueForMoney:
64 | return "비싸요"
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Extension/String+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/06/14.
6 | //
7 |
8 | import UIKit
9 |
10 | extension String {
11 | /// 취소선을 그어줍니다.
12 | /// - Parameter color: 취소선 색
13 | func strikeThrough(with color: UIColor) -> NSMutableAttributedString {
14 | let attributedString = NSMutableAttributedString(string: self)
15 | let range = NSMakeRange(0, attributedString.length)
16 |
17 | attributedString.addAttribute(
18 | NSAttributedString.Key.strikethroughStyle,
19 | value: NSUnderlineStyle.single.rawValue,
20 | range: range
21 | )
22 | attributedString.addAttribute(
23 | NSAttributedString.Key.strikethroughColor,
24 | value: color,
25 | range: range
26 | )
27 | return attributedString
28 | }
29 |
30 | /// + "원"
31 | func addWon() -> String {
32 | return self + "원"
33 | }
34 |
35 | var encodedURLString: String? {
36 | return self.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
37 | }
38 |
39 | var date: Date? {
40 | let dateFormatter = DateFormatter()
41 | dateFormatter.dateFormat = "yyyy-MM-dd"
42 | dateFormatter.timeZone = .current
43 | return dateFormatter.date(from: self)
44 | }
45 |
46 | func isBackSpace() -> Bool {
47 | if let char = self.cString(using: String.Encoding.utf8) {
48 | let isBackSpace = strcmp(char, "\\b") == -92
49 | if isBackSpace { return true }
50 | }
51 | return false
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/ProductDetail/Subview/ImageCell/ProductDetailImageCell+ViewHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProductDetailImageCell+ViewHolder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 김진우 on 2023/09/10.
6 | //
7 |
8 | import UIKit
9 |
10 | import SnapKit
11 |
12 | extension ProductDetailImageCell {
13 | final class ViewHolder: ViewHolderable {
14 | // MARK: - Declaration
15 | enum Size {
16 | static let imageViewSize: CGFloat = 200
17 | static let imageViewTopBottomInset: CGFloat = 60
18 | }
19 |
20 | // MARK: - UI Component
21 | let contentView: UIView = {
22 | let view = UIView(frame: .zero)
23 | return view
24 | }()
25 |
26 | let imageView: UIImageView = {
27 | let imageView = UIImageView(frame: .zero)
28 | imageView.contentMode = .scaleAspectFit
29 | return imageView
30 | }()
31 |
32 | // MARK: - Interface
33 | func place(in view: UIView) {
34 | view.addSubview(contentView)
35 |
36 | contentView.addSubview(imageView)
37 | }
38 |
39 | func configureConstraints(for view: UIView) {
40 | contentView.snp.makeConstraints { make in
41 | make.edges.equalToSuperview()
42 | }
43 |
44 | imageView.snp.makeConstraints { make in
45 | make.size.equalTo(Size.imageViewSize)
46 | make.centerX.equalToSuperview()
47 | make.top.bottom.equalToSuperview().inset(Size.imageViewTopBottomInset)
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Pyonsnal-Color/Pyonsnal-Color/Networking/NetworkRequestBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkRequestBuilder.swift
3 | // Pyonsnal-Color
4 | //
5 | // Created by 조소정 on 2023/07/03.
6 | //
7 |
8 | import Foundation
9 | import Alamofire
10 |
11 | protocol NetworkRequestBuilder: URLRequestConvertible {
12 | var urlString: String { get }
13 | var path: String { get }
14 | var queryItems: [URLQueryItem]? { get }
15 | var method: HTTPMethod { get }
16 | var headers: [HTTPHeader]? { get }
17 | var body: [String: Any]? { get }
18 | }
19 |
20 | extension NetworkRequestBuilder {
21 |
22 | func asURLRequest() throws -> URLRequest {
23 | let baseURL = try urlString.asURL().appendingPathComponent(path, isDirectory: false)
24 | var component = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)
25 |
26 | // set queryItem
27 | let urlQueryItems = queryItems?.compactMap { $0 }
28 | component?.queryItems = urlQueryItems
29 |
30 | let requestURL = component?.url ?? baseURL
31 | var urlRequest = URLRequest(url: requestURL)
32 |
33 | // set method
34 | urlRequest.httpMethod = method.rawValue
35 |
36 | // set body
37 | if let body {
38 | urlRequest.httpBody = try JSONSerialization.data(withJSONObject: body,
39 | options: [])
40 | }
41 |
42 | // set header
43 | if let headers {
44 | headers.forEach { header in
45 | urlRequest.addValue(header.value, forHTTPHeaderField: header.name)
46 | }
47 | }
48 | return urlRequest
49 | }
50 | }
51 |
--------------------------------------------------------------------------------