├── Gemfile ├── Tuist ├── master.key ├── Config.swift └── Dependencies.swift ├── Plugins └── Trinap │ ├── Sources │ └── tuist-my-cli │ │ └── main.swift │ ├── Plugin.swift │ ├── ProjectDescriptionHelpers │ └── LocalHelper.swift │ └── Package.swift ├── Trinap ├── Resources │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── Colors │ │ │ ├── Contents.json │ │ │ ├── Blacks │ │ │ │ ├── Contents.json │ │ │ │ ├── Black.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Border.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray20.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray40.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Background.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Disabled.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Subtext.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Subtext2.colorset │ │ │ │ │ └── Contents.json │ │ │ │ └── White.colorset │ │ │ │ │ └── Contents.json │ │ │ ├── Error.colorset │ │ │ │ └── Contents.json │ │ │ ├── Sub1.colorset │ │ │ │ └── Contents.json │ │ │ ├── Sub2.colorset │ │ │ │ └── Contents.json │ │ │ ├── Secondary.colorset │ │ │ │ └── Contents.json │ │ │ └── Primary.colorset │ │ │ │ └── Contents.json │ │ ├── Images │ │ │ ├── Contents.json │ │ │ ├── chat.imageset │ │ │ │ ├── chat.png │ │ │ │ ├── chat@2x.png │ │ │ │ ├── chat@3x.png │ │ │ │ └── Contents.json │ │ │ ├── home.imageset │ │ │ │ ├── home.png │ │ │ │ ├── home@2x.png │ │ │ │ ├── home@3x.png │ │ │ │ └── Contents.json │ │ │ ├── user.imageset │ │ │ │ ├── user.png │ │ │ │ ├── user@2x.png │ │ │ │ ├── user@3x.png │ │ │ │ └── Contents.json │ │ │ ├── checkBox.imageset │ │ │ │ ├── checkBox.png │ │ │ │ ├── checkBox@2x.png │ │ │ │ ├── checkBox@3x.png │ │ │ │ └── Contents.json │ │ │ ├── chat_plus.imageset │ │ │ │ ├── Chat=Plus.png │ │ │ │ ├── Chat=Plus@2x.png │ │ │ │ ├── Chat=Plus@3x.png │ │ │ │ └── Contents.json │ │ │ ├── dotdotdot.imageset │ │ │ │ ├── dotdotdot.png │ │ │ │ └── Contents.json │ │ │ ├── logo_apple.imageset │ │ │ │ ├── logo_apple.png │ │ │ │ ├── logo_apple@2x.png │ │ │ │ ├── logo_apple@3x.png │ │ │ │ └── Contents.json │ │ │ ├── CustomerPin.imageset │ │ │ │ ├── CustomerPin.png │ │ │ │ ├── CustomerPin@2x.png │ │ │ │ ├── CustomerPin@3x.png │ │ │ │ └── Contents.json │ │ │ ├── reservation.imageset │ │ │ │ ├── reservation.png │ │ │ │ ├── reservation@2x.png │ │ │ │ ├── reservation@3x.png │ │ │ │ └── Contents.json │ │ │ ├── select_home.imageset │ │ │ │ ├── select_home.png │ │ │ │ ├── select_home@2x.png │ │ │ │ ├── select_home@3x.png │ │ │ │ └── Contents.json │ │ │ ├── star_review.imageset │ │ │ │ ├── star_review.png │ │ │ │ ├── star_review@2x.png │ │ │ │ ├── star_review@3x.png │ │ │ │ └── Contents.json │ │ │ ├── select_user.imageset │ │ │ │ ├── selecte_user.png │ │ │ │ ├── selecte_user@2x.png │ │ │ │ ├── selecte_user@3x.png │ │ │ │ └── Contents.json │ │ │ ├── Logo_Vertical.imageset │ │ │ │ ├── logo_vertical.png │ │ │ │ ├── logo_vertical2x.png │ │ │ │ ├── logo_vertical3x.png │ │ │ │ └── Contents.json │ │ │ ├── checkBox_fill.imageset │ │ │ │ ├── checkBox_fill.png │ │ │ │ ├── checkBox_fill@2x.png │ │ │ │ ├── checkBox_fill@3x.png │ │ │ │ └── Contents.json │ │ │ ├── selected_chat.imageset │ │ │ │ ├── selected_chat.png │ │ │ │ ├── selected_chat@2x.png │ │ │ │ ├── selected_chat@3x.png │ │ │ │ └── Contents.json │ │ │ ├── selected_mark.imageset │ │ │ │ ├── selected_mark.png │ │ │ │ ├── selected_mark@2x.png │ │ │ │ ├── selected_mark@3x.png │ │ │ │ └── Contents.json │ │ │ ├── CustomerTracked.imageset │ │ │ │ ├── CustomerTracked.png │ │ │ │ ├── CustomerTracked@2x.png │ │ │ │ ├── CustomerTracked@3x.png │ │ │ │ └── Contents.json │ │ │ ├── PhotographerPin.imageset │ │ │ │ ├── PhotographerPin.png │ │ │ │ ├── PhotographerPin@2x.png │ │ │ │ ├── PhotographerPin@3x.png │ │ │ │ └── Contents.json │ │ │ ├── PlaceholderImage.imageset │ │ │ │ ├── PlaceholderImage.png │ │ │ │ ├── PlaceholderImage@2x.png │ │ │ │ ├── PlaceholderImage@3x.png │ │ │ │ └── Contents.json │ │ │ ├── star_fill_review.imageset │ │ │ │ ├── star_fill_review.png │ │ │ │ ├── star_fill_review@2x.png │ │ │ │ ├── star_fill_review@3x.png │ │ │ │ └── Contents.json │ │ │ ├── CustomerUntracked.imageset │ │ │ │ ├── CustomerUntracked.png │ │ │ │ ├── CustomerUntracked@2x.png │ │ │ │ ├── CustomerUntracked@3x.png │ │ │ │ └── Contents.json │ │ │ ├── sendChat_disabled.imageset │ │ │ │ ├── Chat=Send_disabled.png │ │ │ │ ├── Chat=Send_disabled@2x.png │ │ │ │ ├── Chat=Send_disabled@3x.png │ │ │ │ └── Contents.json │ │ │ ├── sendChat_enabled.imageset │ │ │ │ ├── Chat=Send_enabled.png │ │ │ │ ├── Chat=Send_enabled@2x.png │ │ │ │ ├── Chat=Send_enabled@3x.png │ │ │ │ └── Contents.json │ │ │ ├── PhotographerTracked.imageset │ │ │ │ ├── PhotographerTracked.png │ │ │ │ ├── PhotographerTracked@2x.png │ │ │ │ ├── PhotographerTracked@3x.png │ │ │ │ └── Contents.json │ │ │ ├── selected_reservation.imageset │ │ │ │ ├── selected_reservation.png │ │ │ │ ├── selected_reservation@2x.png │ │ │ │ ├── selected_reservation@3x.png │ │ │ │ └── Contents.json │ │ │ ├── PhotographerUntracked.imageset │ │ │ │ ├── PhotographerUntracked.png │ │ │ │ ├── PhotographerUntracked@2x.png │ │ │ │ ├── PhotographerUntracked@3x.png │ │ │ │ └── Contents.json │ │ │ ├── LocationShareBackButton.imageset │ │ │ │ ├── LocationShareBackButton.png │ │ │ │ ├── LocationShareBackButton@2x.png │ │ │ │ ├── LocationShareBackButton@3x.png │ │ │ │ └── Contents.json │ │ │ └── reviewStar.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── reviewStar.svg │ │ └── AppIcon.appiconset │ │ │ ├── AppIcon.png │ │ │ └── Contents.json │ └── Font │ │ ├── Pretendard-Bold.otf │ │ ├── Pretendard-Medium.otf │ │ ├── Pretendard-Regular.otf │ │ └── Pretendard-SemiBold.otf └── Sources │ ├── Utils │ ├── UserDefaultKey.swift │ ├── LocalError.swift │ ├── TokenManager │ │ ├── KeychainAccount.swift │ │ ├── TokenManagerError.swift │ │ └── TokenManager.swift │ ├── Encodable+.swift │ ├── URLConstants.swift │ ├── String+.swift │ ├── Dictionary+.swift │ ├── Array+.swift │ └── Logger.swift │ ├── Domain │ ├── Models │ │ ├── Photographer │ │ │ ├── Picture.swift │ │ │ ├── PhotographerSection.swift │ │ │ └── Photographer.swift │ │ ├── Review │ │ │ ├── ReviewSummary.swift │ │ │ ├── UserReview.swift │ │ │ ├── Review.swift │ │ │ └── ReviewInformation.swift │ │ ├── OpenSource │ │ │ └── OpenSourceInfo.swift │ │ ├── SignInResult.swift │ │ ├── Coordinate.swift │ │ ├── Contact.swift │ │ ├── ReservationDate.swift │ │ ├── SharedLocation.swift │ │ ├── Space.swift │ │ ├── Chat │ │ │ ├── Chatroom.swift │ │ │ ├── Chat.swift │ │ │ └── ChatPreview.swift │ │ ├── User.swift │ │ ├── Filter │ │ │ ├── ReservationFilter.swift │ │ │ ├── PhotographerFilter.swift │ │ │ └── TagType.swift │ │ └── Block.swift │ ├── UseCases │ │ ├── Chat │ │ │ ├── Protocols │ │ │ │ ├── LeaveChatroomUseCase.swift │ │ │ │ ├── ObserveChatUseCase.swift │ │ │ │ ├── ObserveLastChatUseCase.swift │ │ │ │ ├── UpdateIsCheckedUseCase.swift │ │ │ │ ├── CreateChatroomUseCase.swift │ │ │ │ ├── SendFirstChatUseCase.swift │ │ │ │ └── SendChatUseCase.swift │ │ │ ├── DefaultLeaveChatroomUseCase.swift │ │ │ ├── DefaultObserveLastChatUseCase.swift │ │ │ ├── DefaultUpdateIsCheckedUseCase.swift │ │ │ ├── DefaultSendFirstChatUseCase.swift │ │ │ ├── DefaultSendChatUseCase.swift │ │ │ └── DefaultCreateChatroomUseCase.swift │ │ ├── OpenSource │ │ │ ├── FetchOpenSourceListUseCase.swift │ │ │ └── DefaultFetchOpenSourceListUseCase.swift │ │ ├── LocationShare │ │ │ ├── EndLocationShareUseCase.swift │ │ │ ├── ObserveLocationUseCase.swift │ │ │ ├── UpdateLocationUseCase.swift │ │ │ ├── DefaultEndLocationShareUseCase.swift │ │ │ ├── DefaultObserveLocationUseCase.swift │ │ │ └── DefaultUpdateLocationUseCase.swift │ │ ├── UploadImageUseCase.swift │ │ ├── Auth │ │ │ ├── DropOut │ │ │ │ └── DropOutUseCase.swift │ │ │ ├── SignOut │ │ │ │ ├── SignOutUseCase.swift │ │ │ │ └── DefaultSignOutUseCase.swift │ │ │ └── SignIn │ │ │ │ ├── CreateUserUseCase.swift │ │ │ │ └── SignInUseCase.swift │ │ ├── Reservation │ │ │ ├── Protocols │ │ │ │ ├── FetchReservationUseCase.swift │ │ │ │ ├── CompletePhotoshootUseCase.swift │ │ │ │ ├── FetchReservationUserTypeUseCase.swift │ │ │ │ ├── AcceptReservationRequestUseCase.swift │ │ │ │ ├── CancelReservationRequestUseCase.swift │ │ │ │ ├── CreateReservationUseCase.swift │ │ │ │ ├── FetchReservationPreviewsUseCase.swift │ │ │ │ └── CreateReservationDateUseCase.swift │ │ │ ├── DefaultFetchReservationUserTypeUseCase.swift │ │ │ ├── DefaultCompletePhotoshootUseCase.swift │ │ │ ├── DefaultAcceptReservationRequestUseCase.swift │ │ │ ├── DefaultCancelReservationRequestUseCase.swift │ │ │ └── DefaultCreateReservationUseCase.swift │ │ ├── Photographer │ │ │ ├── Protocols │ │ │ │ ├── ConvertDateToStringUseCase.swift │ │ │ │ ├── FetchPhotographerUserUseCase.swift │ │ │ │ ├── FetchPhotographerUseCase.swift │ │ │ │ ├── FetchPhotographerPreviewsUseCase.swift │ │ │ │ ├── EditPortfolioPictureUseCase.swift │ │ │ │ └── EditPhotographerUseCase.swift │ │ │ ├── DefaultConvertDateToStringUseCase.swift │ │ │ └── DefaultFetchPhotographerUseCase.swift │ │ ├── ChatPreviews │ │ │ └── FetchChatPreviewsUseCase.swift │ │ ├── Search │ │ │ ├── Protocol │ │ │ │ ├── SearchLocationUseCase.swift │ │ │ │ └── FetchCurrentLocationUseCase.swift │ │ │ ├── DefaultSearchLocationUseCase.swift │ │ │ └── DefaultFetchCurrentLocationUseCase.swift │ │ ├── Block │ │ │ ├── Protocols │ │ │ │ ├── RemoveBlockUseCase.swift │ │ │ │ ├── FetchBlockedUsersUseCase.swift │ │ │ │ └── CreateBlockUseCase.swift │ │ │ ├── DefaultRemoveBlockUseCase.swift │ │ │ └── DefaultCreateBlockUseCase.swift │ │ ├── Sue │ │ │ ├── Protocols │ │ │ │ └── CreateSueUseCase.swift │ │ │ └── DefaultCreateSueUseCase.swift │ │ ├── MyPage │ │ │ ├── FetchUserUseCase.swift │ │ │ ├── EditUserUseCase.swift │ │ │ ├── DefaultEditUserUseCase.swift │ │ │ └── DefaultFetchUserUseCase.swift │ │ ├── Review │ │ │ ├── Ptotocols │ │ │ │ └── FetchReviewInformationUseCase.swift │ │ │ ├── CreateReviewUseCase.swift │ │ │ ├── FetchReviewUseCase.swift │ │ │ └── DefaultCreateReviewUseCase.swift │ │ ├── DefaultUploadImageUseCase.swift │ │ └── Contact │ │ │ ├── CreateContactUseCase.swift │ │ │ └── FetchContactUseCase.swift │ └── Repositories │ │ ├── Image │ │ └── UploadImageRepository.swift │ │ ├── OpenSource │ │ └── OpenSourceListRepository.swift │ │ ├── Sue │ │ └── SueRepository.swift │ │ ├── Location │ │ └── LocationRepository.swift │ │ ├── Block │ │ └── BlockRepository.swift │ │ ├── Review │ │ └── ReviewRepository.swift │ │ ├── Map │ │ └── MapRepository.swift │ │ ├── Chat │ │ ├── ChatRepository.swift │ │ └── ChatroomRepository.swift │ │ ├── Auth │ │ └── AuthRepository.swift │ │ ├── Reservation │ │ └── ReservationRepository.swift │ │ ├── User │ │ └── UserRepository.swift │ │ └── Photographer │ │ └── PhotographerRepository.swift │ ├── Data │ ├── DTO │ │ ├── NicknameDTO.swift │ │ ├── SueDTO.swift │ │ ├── ContactDTO.swift │ │ ├── OpenSourceInfoDTO.swift │ │ ├── UserDTO.swift │ │ ├── ChatroomDTO.swift │ │ ├── ReviewDTO.swift │ │ ├── BlockDTO.swift │ │ └── ChatDTO.swift │ ├── NetworkService │ │ ├── NetworkService.swift │ │ ├── NetworkError.swift │ │ └── DefaultNetworkService.swift │ ├── Repositories │ │ ├── Fake │ │ │ ├── FakeError.swift │ │ │ ├── FakeUploadImageRepository.swift │ │ │ └── FakeMapRepository.swift │ │ ├── Image │ │ │ └── DefaultUploadImageRepository.swift │ │ └── OpenSource │ │ │ └── DefaultOpenSourceListRepository.swift │ └── Endpoint │ │ ├── RandomNicknameEndpoint.swift │ │ └── TokenEndpoint.swift │ ├── Presenter │ ├── TabBar │ │ ├── Reservation │ │ │ └── Detail │ │ │ │ └── HandleStatus │ │ │ │ ├── ReservationStatusConvertible.swift │ │ │ │ ├── ReservationUseCaseExecutable.swift │ │ │ │ ├── ReservationError.swift │ │ │ │ └── ReservationStatusConfigurations.swift │ │ ├── Chat │ │ │ ├── Location │ │ │ │ └── TrinapAnnotationView.swift │ │ │ ├── Cell │ │ │ │ ├── ReservationChatCell.swift │ │ │ │ ├── LocationShareChatCell.swift │ │ │ │ └── ChatContentView.swift │ │ │ ├── Custom │ │ │ │ └── UnreadAccessoryView.swift │ │ │ └── ChatDetail │ │ │ │ └── ChatTableView.swift │ │ ├── MyPage │ │ │ ├── MyPage │ │ │ │ └── Tableview │ │ │ │ │ ├── MyPageSectionHeader.swift │ │ │ │ │ └── MyPageSwitchRow.swift │ │ │ └── Photographer │ │ │ │ └── ColletionView │ │ │ │ └── EditPhotographerPhotoHeaderView.swift │ │ ├── Main │ │ │ ├── SelectReservationDate │ │ │ │ └── TitleSectionHeaderView.swift │ │ │ └── PhotographerDetail │ │ │ │ └── PhotographerDetailDataSource.swift │ │ └── Coordinator │ │ │ └── TabBarPageType.swift │ └── Common │ │ ├── Extension │ │ ├── UIView+AddSubviews.swift │ │ ├── UITableView+Reusable.swift │ │ ├── MKAnnotationView+Reusable.swift │ │ ├── UIViewController+.swift │ │ ├── Date+ProperText.swift │ │ ├── UIAlertController+Builder.swift │ │ └── UINavigationController+.swift │ │ ├── ViewModelType.swift │ │ ├── Reusable │ │ ├── Divider.swift │ │ ├── PaddingLabel.swift │ │ └── PlaceHolderView.swift │ │ └── Base │ │ ├── BaseView.swift │ │ ├── BaseCollectionViewCell.swift │ │ └── BaseCollectionReusableView.swift │ └── App │ ├── SceneDelegate.swift │ └── Splash │ └── SplashViewModel.swift ├── .github ├── ISSUE_TEMPLATE │ └── trinap-issue-template.md └── PULL_REQUEST_TEMPLATE.md ├── Queenfisher └── Sources │ ├── ImageCache │ ├── CacheableImage.swift │ ├── ImageCacheError.swift │ ├── ImageCache.swift │ └── ImageCacheConfig.swift │ └── General │ └── Queenfisher.swift ├── Scripts ├── SwiftLintRunScript.sh └── UpdatePackageRunScript.sh ├── fastlane ├── Appfile ├── Matchfile └── README.md ├── Trinap.entitlements ├── FirestoreService └── Sources │ └── FireStore │ └── FireStoreCollectionName.swift ├── LocationCache └── Sources │ ├── General │ ├── LocationCacheError.swift │ ├── CLGeocoder+Cache.swift │ └── LocationCacheWrapper.swift │ └── Cache │ └── MemoryLocationCache.swift ├── Than └── Sources │ └── Than.swift └── TrinapTests └── Sources └── TrinapTests.swift /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /Tuist/master.key: -------------------------------------------------------------------------------- 1 | vLZVCrYeFX7HVql0wfCwFZO2vc9WqzHVsi70IjG5p48= 2 | -------------------------------------------------------------------------------- /Plugins/Trinap/Sources/tuist-my-cli/main.swift: -------------------------------------------------------------------------------- 1 | print("Hello, from your Tuist Task") -------------------------------------------------------------------------------- /Tuist/Config.swift: -------------------------------------------------------------------------------- 1 | import ProjectDescription 2 | 3 | let config = Config() 4 | -------------------------------------------------------------------------------- /Plugins/Trinap/Plugin.swift: -------------------------------------------------------------------------------- 1 | import ProjectDescription 2 | 3 | let plugin = Plugin(name: "MyPlugin") -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Trinap/Resources/Font/Pretendard-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Font/Pretendard-Bold.otf -------------------------------------------------------------------------------- /Trinap/Resources/Font/Pretendard-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Font/Pretendard-Medium.otf -------------------------------------------------------------------------------- /Trinap/Resources/Font/Pretendard-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Font/Pretendard-Regular.otf -------------------------------------------------------------------------------- /Trinap/Resources/Font/Pretendard-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Font/Pretendard-SemiBold.otf -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/home.imageset/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/home.imageset/home.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/user.imageset/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/user.imageset/user.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat.imageset/chat@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/home.imageset/home@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/home.imageset/home@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/home.imageset/home@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/home.imageset/home@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/user.imageset/user@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/user.imageset/user@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/user.imageset/user@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/user.imageset/user@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/checkBox@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/dotdotdot.imageset/dotdotdot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/dotdotdot.imageset/dotdotdot.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Chat=Plus@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/CustomerPin@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/logo_apple@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/reservation.imageset/reservation@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_home.imageset/select_home@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_review.imageset/star_review@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/select_user.imageset/selecte_user@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/logo_vertical3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/checkBox_fill@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/selected_chat@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/selected_mark@3x.png -------------------------------------------------------------------------------- /Plugins/Trinap/ProjectDescriptionHelpers/LocalHelper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct LocalHelper { 4 | let name: String 5 | 6 | public init(name: String) { 7 | self.name = name 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/CustomerTracked@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/PhotographerPin@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/PlaceholderImage@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/star_fill_review@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/CustomerUntracked@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Chat=Send_enabled@3x.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/trinap-issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Trinap Issue Template 3 | about: Trinap의 이슈 템플릿입니다. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 요약 11 | 12 | # 상세 설명 13 | 14 | # 체크리스트 15 | - [ ] 16 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Chat=Send_disabled@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/PhotographerTracked@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/PhotographerUntracked@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/selected_reservation@3x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton@2x.png -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2022/iOS02-Trinap/HEAD/Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/LocationShareBackButton@3x.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # 작업 내용 2 | > 해결한 이슈 넘버와 설명을 적어주세요 3 | 4 | resolved: 5 | 6 | # 질문 및 특이사항 7 | > 해결하지 못한 부분이나 팀원들에게 알려줄 사항을 적어주세요 8 | 9 | # 체크리스트 10 | - [ ] 빌드가 되는 코드인가요? 11 | - [ ] Warning이 없는 코드인가요? 12 | - [ ] Merge할 브랜치가 올바른가요? 13 | - [ ] 코딩 컨벤션이 올바른가요? 14 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/UserDefaultKey.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDefaultKey.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum UserDefaultKey { 12 | static let isPhotographer = "isPhotographer" 13 | } 14 | -------------------------------------------------------------------------------- /Trinap/Resources/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 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Photographer/Picture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Picture.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Picture: Hashable { 12 | let isEditable: Bool 13 | let picture: String? 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Review/ReviewSummary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewSummary.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/25. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ReviewSummary: Hashable { 12 | let rating: Double 13 | let count: Int 14 | } 15 | -------------------------------------------------------------------------------- /Queenfisher/Sources/ImageCache/CacheableImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheableImage.swift 3 | // Queenfisher 4 | // 5 | // Created by kimchansoo on 2022/12/28. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct CacheableImage: Codable { 12 | var imageData: QFData 13 | var etag: String 14 | } 15 | -------------------------------------------------------------------------------- /Scripts/SwiftLintRunScript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SwiftLintRunScript.sh 4 | # Manifests 5 | # 6 | # Created by 김세영 on 2022/11/10. 7 | # 8 | 9 | export PATH="$PATH:/opt/homebrew/bin" 10 | if which swiftlint >/dev/null; then 11 | swiftlint 12 | else 13 | echo "warning: SwiftLint not installed, download form https://github.com/realm/SwiftLint" 14 | fi 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/NicknameDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NicknameDTO.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct NicknameDTO: Decodable { 12 | 13 | // MARK: - Properties 14 | let words: [String] 15 | let seed: String 16 | } 17 | -------------------------------------------------------------------------------- /Plugins/Trinap/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.4 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "MyPlugin", 7 | products: [ 8 | .executable(name: "tuist-my-cli", targets: ["tuist-my-cli"]), 9 | ], 10 | targets: [ 11 | .executableTarget( 12 | name: "tuist-my-cli" 13 | ), 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/OpenSource/OpenSourceInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSourceInfo.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct OpenSourceInfo: Hashable { 12 | var name: String 13 | let version: String 14 | var url: URL? 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/LeaveChatroomUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LeaveChatroomUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol LeaveChatroomUseCase { 12 | 13 | func execute(chatroomId: String) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("com.tnzkm.Trinap") # The bundle identifier of your app 2 | apple_id("yy0867@gmail.com") # Your Apple Developer Portal username 3 | 4 | itc_team_id("123946758") # App Store Connect Team ID 5 | team_id("GTB6BR222W") # Developer Portal Team ID 6 | 7 | # For more information about the Appfile, see: 8 | # https://docs.fastlane.tools/advanced/#appfile 9 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/OpenSource/FetchOpenSourceListUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchOpenSourceListUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol FetchOpenSourceListUseCase { 12 | func fetchOpenSource() -> [OpenSourceInfo] 13 | } 14 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/EndLocationShareUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EndLocationShareUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/25. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol EndLocationShareUseCase { 12 | 13 | func execute(chatroomId: String) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/UploadImageUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UploadImageUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol UploadImageUseCase { 14 | 15 | func execute(_ imageData: Data) -> Observable 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/SignInResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SignInResult.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/18. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// SignIn 요청에 대한 응답으로 UseCase 사용 13 | enum SignInResult { 14 | 15 | case signIn 16 | case signUp 17 | case failure 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/ObserveLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserveLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ObserveLocationUseCase { 12 | 13 | func execute(chatroomId: String) -> Observable<[SharedLocation]> 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Reservation/Detail/HandleStatus/ReservationStatusConvertible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationStatusConvertible.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/02. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | protocol ReservationStatusConvertible { 10 | 11 | func convert() -> ReservationStatusConfigurations 12 | } 13 | -------------------------------------------------------------------------------- /Queenfisher/Sources/ImageCache/ImageCacheError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCacheError.swift 3 | // Queenfisher 4 | // 5 | // Created by kimchansoo on 2022/12/28. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ImageCacheError: Error { 12 | case imageNotModifiedError 13 | case httpResponseTransformError 14 | case unknownError 15 | } 16 | -------------------------------------------------------------------------------- /Trinap.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.applesignin 8 | 9 | Default 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Image/UploadImageRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UploadImageRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol UploadImageRepository { 14 | 15 | func upload(image data: Data) -> Observable 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Auth/DropOut/DropOutUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DropOutUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/01. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol DropOutUseCase { 14 | 15 | // MARK: - Methods 16 | func dropOut() -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Auth/SignOut/SignOutUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SignOutUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol SignOutUseCase { 14 | 15 | // MARK: - Methods 16 | func signOut() -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/ObserveChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserveChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ObserveChatUseCase { 12 | 13 | // MARK: - Methods 14 | func execute(chatroomId: String) -> Observable<[Chat]> 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/UpdateLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UpdateLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol UpdateLocationUseCase { 12 | 13 | func execute(chatroomId: String, location: Coordinate) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/FetchReservationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchReservationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/01. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol FetchReservationUseCase { 12 | 13 | func execute(reservationId: String) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/UIView+AddSubviews.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+AddSubviews.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/20. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIView { 12 | 13 | func addSubviews(_ subviews: [UIView]) { 14 | subviews.forEach(self.addSubview) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/ConvertDateToStringUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConvertDateToStringUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ConvertDateToStringUseCase { 12 | func convert(startDate: Date, endDate: Date) -> String? 13 | } 14 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Review/UserReview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserReivew.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 작가에게 작성된 리뷰 12 | struct UserReview: Hashable { 13 | let user: User 14 | let contents: String 15 | let rating: Int 16 | let createdAt: Date 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/ObserveLastChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserveLastChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ObserveLastChatUseCase { 12 | 13 | // MARK: - Methods 14 | func execute(chatroomId: String) -> Observable 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/ChatPreviews/FetchChatPreviewsUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ObserveChatPreviewsUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ObserveChatPreviewsUseCase { 12 | 13 | // MARK: - Methods 14 | func execute() -> Observable<[ChatPreview]> 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/CompletePhotoshootUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompletePhotoshootUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol CompletePhotoshootUseCase { 12 | 13 | func execute(reservation: Reservation) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/LocalError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocalError.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum LocalError: Error { 12 | case structToDictionaryError 13 | case signInError 14 | case addressError 15 | case locationAuthError 16 | case tokenError 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/NetworkService/NetworkService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkService.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol NetworkService { 14 | 15 | // MARK: - Methods 16 | func request(_ endpoint: Endpoint) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Coordinate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Location.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Coordinate: Encodable { 12 | let lat: Double 13 | let lng: Double 14 | 15 | static var seoulCoordinate = Coordinate(lat: 37.553836, lng: 126.969652) 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/OpenSource/OpenSourceListRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSourceListRepository.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol OpenSourceListRepository { 12 | 13 | // MARK: - Methods 14 | func fetchOpenSourceList() -> [OpenSourceInfo] 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/UpdateIsCheckedUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UpdateIsCheckedUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol UpdateIsCheckedUseCase { 12 | 13 | func execute(chatroomId: String, chatId: String, toState state: Bool) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/FetchReservationUserTypeUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchReservationUserTypeUseCAse.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/02. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | protocol FetchReservationUserTypeUseCase { 10 | 11 | func execute(customerId: String, photographerId: String) -> Reservation.UserType? 12 | } 13 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Search/Protocol/SearchLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol SearchLocationUseCase { 12 | 13 | // MARK: Methods 14 | func fetchSearchList(with searchText: String) -> Observable<[Space]> 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/AcceptReservationRequestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AcceptReservationRequestUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol AcceptReservationRequestUseCase { 12 | 13 | func execute(reservation: Reservation) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/CancelReservationRequestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CancelReservationRequestUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol CancelReservationRequestUseCase { 12 | 13 | func execute(reservation: Reservation) -> Observable 14 | } 15 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Block/Protocols/RemoveBlockUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RemoveBlockUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol RemoveBlockUseCase { 14 | 15 | // MARK: Methods 16 | func removeBlockUser(blockId: String) -> Single 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/FetchPhotographerUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchPhotographerUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchPhotographerUserUseCase { 14 | func fetch(userId: String) -> Observable 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/CreateChatroomUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateChatroomUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/05. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateChatroomUseCase { 14 | 15 | // MARK: Methods 16 | func create(photographerUserId: String) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Sue/Protocols/CreateSueUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateSueUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateSueUseCase { 14 | 15 | // MARK: Methods 16 | func create(suedUserId: String, contents: Sue.SueContents) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Block/Protocols/FetchBlockedUsersUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchBlockedUsersUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/03. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchBlockedUsersUseCase { 14 | 15 | // MARK: Methods 16 | func fetchBlockedUsers() -> Observable<[Block.BlockedUser]> 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/SendFirstChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SendFirstChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/05. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol SendFirstChatUseCase { 14 | 15 | // MARK: Methods 16 | func send(chatroomId: String, reservationId: String) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Sue/SueRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SueRepository.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol SueRepository { 14 | 15 | // MARK: Methods 16 | func sueUser(suedUserId: String, contents: String) -> Single 17 | func fetchSuedUsers() -> Single<[Sue]> 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/MyPage/FetchUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchUserUseCase { 14 | 15 | // MARK: Methods 16 | func fetchUserInfo() -> Observable 17 | func fetchUserInfo(userId: String) -> Observable 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Search/Protocol/FetchCurrentLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchCurrentLocation.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchCurrentLocationUseCase { 14 | 15 | // MARK: Methods 16 | func fetchCurrentLocation() -> Observable<(Coordinate, String)> 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/dotdotdot.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "dotdotdot.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 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reviewStar.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "reviewStar.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 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/FetchPhotographerUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchPhotographerUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchPhotographerUseCase { 14 | 15 | // MARK: Methods 16 | func fetch(photographerUserId: String?) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Error.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x3D", 9 | "green" : "0x40", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Sub1.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.949", 9 | "green" : "0.984", 10 | "red" : "0.929" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Sub2.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.957", 10 | "red" : "0.949" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Review/Ptotocols/FetchReviewInformationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchReviewInformationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchReviewInformationUseCase { 14 | 15 | // MARK: Methods 16 | func fetch(photographerUserId: String) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Black.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x18", 9 | "green" : "0x18", 10 | "red" : "0x18" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Border.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xF0", 9 | "green" : "0xED", 10 | "red" : "0xEC" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Gray20.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x44", 9 | "green" : "0x3F", 10 | "red" : "0x3E" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Gray40.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x94", 9 | "green" : "0x89", 10 | "red" : "0x86" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Secondary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.557", 10 | "red" : "0.412" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFA", 9 | "green" : "0xF7", 10 | "red" : "0xF7" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Disabled.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xDA", 9 | "green" : "0xD3", 10 | "red" : "0xD0" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Subtext.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x75", 9 | "green" : "0x6C", 10 | "red" : "0x69" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/Subtext2.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xC0", 9 | "green" : "0xB3", 10 | "red" : "0xAF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Blacks/White.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Contact.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactUs.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/06. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Contact: Hashable { 12 | enum State: String, Codable { 13 | case activate, deactivate 14 | } 15 | 16 | let contactId: String 17 | let title: String 18 | let description: String 19 | let createdAt: String 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/ReservationDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationDate.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ReservationTimeSection: String, Hashable { 12 | case startDate = "시작 시간" 13 | case endDate = "종료 시간" 14 | } 15 | 16 | struct ReservationDate: Hashable { 17 | let date: Date 18 | let type: ReservationTimeSection 19 | } 20 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Auth/SignIn/CreateUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateUserUseCase { 14 | 15 | // MARK: - Methods 16 | func createUser(with nickName: String) -> Observable 17 | func createRandomNickname() -> Observable 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Review/CreateReviewUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateReviewUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/18. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateReviewUseCase { 14 | func createReview(photographerId: String, contents: String, rating: Int) -> Observable 15 | func checkButtonEnabled(text: String, rating: Int) -> Bool 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Block/Protocols/CreateBlockUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateBlockUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/03. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateBlockUseCase { 14 | 15 | // MARK: Methods 16 | func create(blockedUserId: String) -> Single 17 | func create(blockedUserId: String, blockId: String) -> Single 18 | } 19 | -------------------------------------------------------------------------------- /FirestoreService/Sources/FireStore/FireStoreCollectionName.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FireStoreCollectionName.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum FireStoreCollection: String { 12 | case blocks, chatrooms, photographers, reservations, reviews, users, chats, locations, contact, sue 13 | 14 | var name: String { 15 | return self.rawValue 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/TokenManager/KeychainAccount.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeychainAccount.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum KeychainAccount: String { 12 | case userId = "com.tnzkm.keychain.userId" 13 | case fcmToken = "com.tnzkm.keychain.fcmToken" 14 | case refreshToken = "com.tnzkm.keychain.refreshToken" 15 | case auth = "com.tnzkm.keychain.firauth" 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/FetchPhotographerPreviewsUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchPhotographerPreviewsUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchPhotographerPreviewsUseCase { 14 | 15 | // MARK: Methods 16 | func fetch(coordinate: Coordinate?, type: TagType) -> Observable<[PhotographerPreview]> 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/ViewModelType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModelType.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ViewModelType: AnyObject { 12 | 13 | associatedtype Input 14 | associatedtype Output 15 | 16 | // MARK: - Properties 17 | var disposeBag: DisposeBag { get } 18 | 19 | // MARK: - Methods 20 | func transform(input: Input) -> Output 21 | } 22 | -------------------------------------------------------------------------------- /LocationCache/Sources/General/LocationCacheError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationCacheError.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum LocationCacheError: LocalizedError { 12 | 13 | case noPlacemark 14 | 15 | public var errorDescription: String? { 16 | switch self { 17 | case .noPlacemark: 18 | return "위치 정보를 확인할 수 없습니다." 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/SharedLocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationShare.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct SharedLocation: Codable { 12 | 13 | let userId: String 14 | let latitude: Double 15 | let longitude: Double 16 | var isMine = false 17 | 18 | private enum CodingKeys: String, CodingKey { 19 | case userId, latitude, longitude 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Space.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Space.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Space { 12 | let id = UUID().uuidString 13 | let name: String 14 | let address: String 15 | let lat: Double 16 | let lng: Double 17 | } 18 | 19 | extension Space: Hashable { 20 | func hash(into hasher: inout Hasher) { 21 | hasher.combine(id) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Location/LocationRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol LocationRepository { 12 | 13 | func observe(chatroomId: String) -> Observable<[SharedLocation]> 14 | func update(chatroomId: String, location: Coordinate) -> Observable 15 | func endShare(chatroomId: String) -> Observable 16 | } 17 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/Protocols/SendChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SendChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol SendChatUseCase { 12 | 13 | func execute(chatType: Chat.ChatType, content: String, chatroomId: String) -> Observable 14 | func execute(imageURL: String, chatroomId: String, imageWidth: Double, imageHeight: Double) -> Observable 15 | } 16 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/TokenManager/TokenManagerError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenManagerError.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum TokenManagerError: LocalizedError { 12 | 13 | case notFound 14 | 15 | var errorDescription: String? { 16 | switch self { 17 | case .notFound: 18 | return "Cannot find token in TokenManager." 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chat.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "chat@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "chat@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "home.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "home@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "home@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/user.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "user.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "user@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "user@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | git_url("https://github.com/chansooo/TrinapCert") 2 | 3 | storage_mode("git") 4 | 5 | type("appstore") # The default type, can be: appstore, adhoc, enterprise or development 6 | 7 | app_identifier("com.tnzkm.Trinap") 8 | # username("yy0867@gmail.com") # Your Apple Developer Portal username 9 | 10 | # For all available options run `fastlane match --help` 11 | # Remove the # in the beginning of the line to enable the other options 12 | 13 | # The docs are available on https://docs.fastlane.tools/actions/match 14 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/MyPage/EditUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EditUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol EditUserUseCase { 14 | func updateProfielInfo(profileImage: String?, nickName: String?) -> Observable 15 | func fetchRandomNickName() -> Observable 16 | func updatePhotographerExposure(_ isOn: Bool) -> Observable 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Colors/Primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.498", 9 | "green" : "0.812", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | }, 20 | "properties" : { 21 | "localizable" : true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Reusable/Divider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Divider.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/01. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import SnapKit 12 | 13 | final class Divider: BaseView { 14 | 15 | init() { 16 | super.init(frame: .zero) 17 | 18 | self.backgroundColor = TrinapAsset.border.color 19 | self.snp.makeConstraints { make in 20 | make.height.equalTo(1) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/chat_plus.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Chat=Plus.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "Chat=Plus@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "Chat=Plus@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "checkBox.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "checkBox@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "checkBox@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Review/Review.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Review.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ReviewTarget: String { 12 | case customer = "creatorUserId" 13 | case photographer = "photographerUserId" 14 | } 15 | 16 | struct Review: Equatable, Hashable { 17 | let reviewId, photographerUserId, creatorUserId, contents, status: String 18 | let createdAt: Date 19 | let rating: Int 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/logo_apple.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo_apple.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo_apple@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "logo_apple@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Chat/Chatroom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Chatroom.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Chatroom { 12 | 13 | enum Status: String, Codable { 14 | case activate, deactivate 15 | } 16 | 17 | // MARK: - Properties 18 | let chatroomId: String 19 | let customerUserId: String 20 | let photographerUserId: String 21 | let status: Status 22 | let updatedAt: Date 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerPin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CustomerPin.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "CustomerPin@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "CustomerPin@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reservation.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "reservation.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "reservation@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "reservation@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "select_home.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "select_home@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "select_home@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_review.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "star_review.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "star_review@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "star_review@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/Logo_Vertical.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo_vertical.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo_vertical2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "logo_vertical3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/select_user.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "selecte_user.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "selecte_user@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "selecte_user@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct User: Hashable { 12 | 13 | enum Status: String, Codable { 14 | case activate, deactivate 15 | } 16 | 17 | // MARK: - Properties 18 | let userId: String 19 | let nickname: String 20 | let profileImage: URL? 21 | let isPhotographer: Bool 22 | let fcmToken: String 23 | let status: Status 24 | } 25 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Auth/SignIn/SignInUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SignInUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | import FirebaseAuth 13 | 14 | protocol SignInUseCase { 15 | 16 | // MARK: - Methods 17 | func signIn(with credential: (OAuthCredential, String)) -> Observable 18 | func autoSignIn() -> Observable 19 | func updateFcmToken() -> Observable 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Review/FetchReviewUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchReviewUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchReviewUseCase { 14 | func fetchAverageReview(photographerUserId: String?) -> Observable 15 | func fetchReviews(userId: String) -> Observable<[UserReview]> 16 | func fetchReviews(photographerUserId: String?) -> Observable<[UserReview]> 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/checkBox_fill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "checkBox_fill.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "checkBox_fill@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "checkBox_fill@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_chat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "selected_chat.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "selected_chat@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "selected_chat@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_mark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "selected_mark.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "selected_mark@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "selected_mark@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Filter/ReservationFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationFilter.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ReservationFilter: Int, CaseIterable, Hashable { 12 | case receive = 0 13 | case send 14 | 15 | var title: String { 16 | switch self { 17 | case .receive: 18 | return "받은 예약" 19 | case .send: 20 | return "보낸 예약" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerTracked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CustomerTracked.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "CustomerTracked@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "CustomerTracked@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerPin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "PhotographerPin.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "PhotographerPin@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "PhotographerPin@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/CreateReservationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateReservationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/01. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateReservationUseCase { 14 | 15 | // MARK: Methods 16 | func create( 17 | photographerUserId: String, 18 | startDate: Date, 19 | endDate: Date, 20 | coordinate: Coordinate 21 | ) -> Observable 22 | } 23 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PlaceholderImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "PlaceholderImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "PlaceholderImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "PlaceholderImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/star_fill_review.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "star_fill_review.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "star_fill_review@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "star_fill_review@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/FetchReservationPreviewsUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchReservationPreviewsUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchReservationPreviewsUseCase { 14 | 15 | // MARK: Methods 16 | func fetchSentReservationPreviews() -> Observable<[Reservation.Preview]> 17 | func fetchReceivedReservationPreviews() -> Observable<[Reservation.Preview]> 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/CustomerUntracked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CustomerUntracked.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "CustomerUntracked@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "CustomerUntracked@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_disabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Chat=Send_disabled.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "Chat=Send_disabled@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "Chat=Send_disabled@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/sendChat_enabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Chat=Send_enabled.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "Chat=Send_enabled@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "Chat=Send_enabled@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerTracked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "PhotographerTracked.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "PhotographerTracked@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "PhotographerTracked@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/selected_reservation.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "selected_reservation.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "selected_reservation@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "selected_reservation@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Repositories/Fake/FakeError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FakeError.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum FakeError: LocalizedError { 12 | 13 | case unknown 14 | case errorAt(String) 15 | 16 | var errorDescription: String? { 17 | switch self { 18 | case .unknown: 19 | return "Fake Error" 20 | case .errorAt(let function): 21 | return "Error from \(function)" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/PhotographerUntracked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "PhotographerUntracked.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "PhotographerUntracked@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "PhotographerUntracked@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/NetworkService/NetworkError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkError.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum NetworkError: LocalizedError { 12 | 13 | case invalidURL 14 | case unknown 15 | 16 | public var errorDescription: String? { 17 | switch self { 18 | case .invalidURL: 19 | return "올바르지 않은 URL입니다." 20 | case .unknown: 21 | return "알 수 없는 오류입니다." 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/LocationShareBackButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LocationShareBackButton.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LocationShareBackButton@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LocationShareBackButton@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Block/BlockRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReportRepository.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol BlockRepository { 14 | 15 | // MARK: Methods 16 | func blockUser(blockedUserId: String) -> Single 17 | func blockUser(blockedUserId: String, blockId: String) -> Single 18 | func removeBlockUser(blockId: String) -> Single 19 | func fetchBlockedUser() -> Single<[Block]> 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Review/ReviewInformation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewInformation.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/26. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ReviewInformation { 12 | let summary: ReviewSummary 13 | let reviews: [UserReview] 14 | 15 | func toDataSource() -> [PhotographerDataSource] { 16 | return [ 17 | [.detail: [.summaryReview(self.summary)]], 18 | [.review: self.reviews.map { PhotographerSection.Item.review($0) } ] 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Review/ReviewRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewRepository.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol ReviewRepository { 14 | 15 | // MARK: - Methods 16 | func fetchReviews(id: String, target: ReviewTarget) -> Observable<[Review]> 17 | func fetchReview(target: ReviewTarget) -> Observable<[Review]> 18 | func createReview(to photograhperId: String, contents: String, rating: Int) -> Observable 19 | } 20 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/Encodable+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Encodable+.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Encodable { 12 | 13 | var asDictionary: [String: Any]? { 14 | guard 15 | let object = try? JSONEncoder().encode(self), 16 | let dictinoary = try? JSONSerialization.jsonObject(with: object, options: []) as? [String: Any] 17 | else { 18 | return nil 19 | } 20 | 21 | return dictinoary 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/EditPortfolioPictureUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EditPortfolioPictureUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol EditPortfolioPictureUseCase { 14 | 15 | // MARK: Methods 16 | func delete(photographer: Photographer, indices: [Int]) -> Observable 17 | func add( 18 | photographerId: String, 19 | currentPictures: [String], 20 | pictureData: Data 21 | ) -> Observable 22 | } 23 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/URLConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLConstants.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum URLConstants { 12 | 13 | static let notificationAuthorization = "app-settings:root=NOTIFICATIONS_ID" 14 | static let photoAuthorization = "app-settings:root=Photos" 15 | static let locationAuthorization = "app-settings:root=LOCATION_SERVICES" 16 | static let placeholderImage = "https://user-images.githubusercontent.com/27603734/208003346-efa615b9-7ef4-4462-b7ea-91b53a5730ab.png" 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Filter/PhotographerFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotographerFilter.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum PhotographerFitler: Int, CaseIterable, Hashable { 12 | case fortpolio = 0 13 | case detail 14 | case review 15 | 16 | var title: String { 17 | switch self { 18 | case .fortpolio: 19 | return "포트폴리오" 20 | case .detail: 21 | return "상세정보" 22 | case .review: 23 | return "리뷰" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Endpoint/RandomNicknameEndpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RandomNicknameEndpoint.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum RandomNicknameEndpoint: String, Endpoint { 12 | case main 13 | 14 | // MARK: - Properties 15 | var baseURL: URL? { return URL(string: "https://nickname.hwanmoo.kr") } 16 | var method: HTTPMethod { return .GET } 17 | var path: String { return "" } 18 | var parameters: HTTPRequestParameter? { return .query(["format": "json", "count": "1", "max_length": "8"])} 19 | } 20 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Photographer/PhotographerSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotographerSection.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum PhotographerSection: Int, Hashable { 12 | 13 | case profile = 0 14 | case photo 15 | case detail 16 | case review 17 | 18 | enum Item: Hashable { 19 | case profile(PhotographerUser) 20 | case photo(Picture?) 21 | case detail(PhotographerUser) 22 | case summaryReview(ReviewSummary) 23 | case review(UserReview) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Map/MapRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MapRepository.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import MapKit 10 | import Foundation 11 | 12 | import RxRelay 13 | import RxSwift 14 | 15 | protocol MapRepository { 16 | // MARK: Properties 17 | var results: BehaviorRelay<[Space]> { get } 18 | 19 | // MARK: Methods 20 | func setSearchText(with searchText: String) 21 | func fetchCurrentLocation() -> Result 22 | func fetchLocationName(using coordinate: Coordinate) -> Observable 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/Protocols/EditPhotographerUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EditPhotographerUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol EditPhotographerUseCase { 14 | 15 | // MARK: Methods 16 | func updatePhotographer(photographer: Photographer) -> Observable 17 | func createPhotographer( 18 | coordinate: Coordinate, 19 | introduction: String, 20 | tags: [TagType], 21 | pricePerHalfHour: Int 22 | ) -> Observable 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Block.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Block.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Block { 12 | 13 | enum BlockStatus: String { 14 | case active 15 | case inactive 16 | } 17 | 18 | // MARK: Properties 19 | let blockId: String 20 | let blockedUserId: String 21 | let userId: String 22 | } 23 | 24 | // MARK: - Mapper struct 25 | extension Block { 26 | 27 | struct BlockedUser: Hashable { 28 | let blockId: String 29 | let blockedUser: User 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/String+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import CryptoKit 10 | import Foundation 11 | 12 | extension String { 13 | 14 | func toSha256() -> String { 15 | let data = Data(self.utf8) 16 | let hashedData = SHA256.hash(data: data) 17 | let hashString = hashedData.compactMap { String(format: "%02x", $0) }.joined() 18 | 19 | return hashString 20 | } 21 | 22 | static var errorDetected: String { 23 | return "오류가 발생했습니다.\n잠시 후 다시 시도해주세요." 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/SueDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SueDTO.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct SueDTO: Codable { 12 | 13 | // MARK: Properties 14 | let sueId: String 15 | let suedUserId: String 16 | let suingUserId: String 17 | let contents: String 18 | 19 | // MARK: Methods 20 | func toModel() -> Sue { 21 | return Sue( 22 | sueId: sueId, 23 | suedUserId: suedUserId, 24 | suingUserId: suingUserId, 25 | contents: contents 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LocationCache/Sources/General/CLGeocoder+Cache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CLGeocoder+Cache.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | extension LocationCacheWrapper where Base: CLGeocoder { 12 | 13 | public func reverseGeocodeLocation(_ location: CLLocation, preferredLocale: Locale? = nil, completionHandler: @escaping (String, Error?) -> Void) { 14 | LocationCache.shared.reverseGeocodeLocation( 15 | location, 16 | preferredLocale: preferredLocale, 17 | completionHandler: completionHandler 18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Chat/ChatRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ChatRepository { 12 | 13 | // MARK: - Methods 14 | func observe(chatroomId: String) -> Observable<[Chat]> 15 | func send(chatType: Chat.ChatType, content: String, at chatroomId: String) -> Observable 16 | func send(imageURL: String, chatroomId: String, imageWidth: Double, imageHeight: Double) -> Observable 17 | func updateIsChecked(chatroomId: String, chatId: String, toState state: Bool) -> Observable 18 | } 19 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/ContactDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactUsDTO.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/06. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ContactDTO: Codable { 12 | let contactId: String 13 | let userId: String 14 | let title: String 15 | let description: String 16 | let createAt: String 17 | let status: Contact.State 18 | 19 | func toModel() -> Contact { 20 | return Contact( 21 | contactId: self.contactId, 22 | title: self.title, 23 | description: self.description, 24 | createdAt: self.createAt 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Chat/ChatroomRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatroomRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ChatroomRepository { 12 | 13 | // MARK: - Methods 14 | func observe() -> Observable<[Chatroom]> 15 | func fetchChatrooms() -> Observable<[Chatroom]> 16 | func updateDate(chatroomId: String) -> Observable 17 | func create(customerUserId: String, photographerUserId: String) -> Observable 18 | func create(photographerUserId: String) -> Observable 19 | func leave(chatroomId: String) -> Single 20 | } 21 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/Dictionary+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary+.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Dictionary { 12 | 13 | func toObject() -> T? where T: Decodable { 14 | guard 15 | let data = try? JSONSerialization.data(withJSONObject: self), 16 | let object = try? JSONDecoder().decode(T.self, from: data) 17 | else { 18 | return nil 19 | } 20 | 21 | return object 22 | } 23 | 24 | func toObject(_ type: T.Type) -> T? where T: Decodable { 25 | return self.toObject() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/Protocols/CreateReservationDateUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateReservationDateUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol CreateReservationDateUseCase { 12 | func createStartDate(date: Date) -> [Date] 13 | func createEndDate(date: Date) -> [Date] 14 | func selectedStartDate(startDate: ReservationDate, endDate: ReservationDate) -> ReservationDate? 15 | func selectedEndDate(startDate: ReservationDate, endDate: ReservationDate) -> ReservationDate? 16 | func createReservationDate(date: Date, minute: Int, type: ReservationTimeSection) -> ReservationDate 17 | } 18 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Reservation/Detail/HandleStatus/ReservationUseCaseExecutable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationUseCaseExecutable.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/02. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | protocol ReservationUseCaseExecutable { 12 | 13 | func executePrimaryAction() -> Observable? 14 | func executeSecondaryAction() -> Observable? 15 | } 16 | 17 | extension ReservationUseCaseExecutable { 18 | 19 | func executePrimaryAction() -> Observable? { 20 | return nil 21 | } 22 | 23 | func executeSecondaryAction() -> Observable? { 24 | return nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultLeaveChatroomUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultLeaveChatroomUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultLeaveChatroomUseCase: LeaveChatroomUseCase { 12 | 13 | // MARK: - Properties 14 | private let repository: ChatroomRepository 15 | 16 | // MARK: - Initializers 17 | init(repository: ChatroomRepository) { 18 | self.repository = repository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatroomId: String) -> Observable { 23 | return repository.leave(chatroomId: chatroomId) 24 | .asObservable() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/DefaultConvertDateToStringUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultConvertDateToStringUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DefaultConvertDateToStringUseCase: ConvertDateToStringUseCase { 12 | 13 | // MARK: Methods 14 | func convert(startDate: Date, endDate: Date) -> String? { 15 | let date = startDate.toString(type: .monthAndDate2) 16 | let startTime = startDate.toString(type: .hourAndMinute) 17 | let endTime = endDate.toString(type: .hourAndMinute) 18 | let dateInfo = "\(date) \(startTime)-\(endTime)\n" 19 | return dateInfo 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LocationCache/Sources/General/LocationCacheWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationCacheWrapper.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | public struct LocationCacheWrapper { 12 | 13 | // MARK: - Properties 14 | public let base: Base 15 | 16 | // MARK: - Methods 17 | public init(base: Base) { 18 | self.base = base 19 | } 20 | } 21 | 22 | public protocol LocationCacheCompatible: AnyObject {} 23 | 24 | public extension LocationCacheCompatible { 25 | 26 | var useCache: LocationCacheWrapper { 27 | return LocationCacheWrapper(base: self) 28 | } 29 | } 30 | 31 | extension CLGeocoder: LocationCacheCompatible {} 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Block/DefaultRemoveBlockUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultRemoveBlockUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultRemoveBlockUseCase: RemoveBlockUseCase { 14 | 15 | // MARK: Properties 16 | private let blockRepository: BlockRepository 17 | 18 | // MARK: Initializers 19 | init(blockRepository: BlockRepository) { 20 | self.blockRepository = blockRepository 21 | } 22 | 23 | // MARK: Methods 24 | func removeBlockUser(blockId: String) -> Single { 25 | return self.blockRepository.removeBlockUser(blockId: blockId) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultObserveLastChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultObserveLastChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultObserveLastChatUseCase: ObserveLastChatUseCase { 14 | 15 | // MARK: - Properties 16 | private let chatUseCase: ChatRepository 17 | 18 | // MARK: - Methods 19 | init(chatUseCase: ChatRepository) { 20 | self.chatUseCase = chatUseCase 21 | } 22 | 23 | func execute(chatroomId: String) -> Observable { 24 | return self.chatUseCase 25 | .observe(chatroomId: chatroomId) 26 | .compactMap { $0.last } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/DefaultEndLocationShareUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultEndLocationShareUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/25. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultEndLocationShareUseCase: EndLocationShareUseCase { 12 | 13 | // MARK: - Properties 14 | private let locationRepository: LocationRepository 15 | 16 | // MARK: - Initializers 17 | init(locationRepository: LocationRepository) { 18 | self.locationRepository = locationRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatroomId: String) -> Observable { 23 | return locationRepository.endShare(chatroomId: chatroomId) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/DefaultObserveLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultObserveLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultObserveLocationUseCase: ObserveLocationUseCase { 12 | 13 | // MARK: - Properties 14 | private let locationRepository: LocationRepository 15 | 16 | // MARK: - Initializers 17 | init(locationRepository: LocationRepository) { 18 | self.locationRepository = locationRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatroomId: String) -> Observable<[SharedLocation]> { 23 | return locationRepository.observe(chatroomId: chatroomId) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/DefaultUploadImageUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultUploadImageUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultUploadImageUseCase: UploadImageUseCase { 14 | 15 | // MARK: - Properties 16 | private let uploadImageRepository: UploadImageRepository 17 | 18 | // MARK: - Initializer 19 | init(uploadImageRepository: UploadImageRepository) { 20 | self.uploadImageRepository = uploadImageRepository 21 | } 22 | 23 | // MARK: - Methods 24 | func execute(_ imageData: Data) -> Observable { 25 | return self.uploadImageRepository.upload(image: imageData) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Resources/Assets.xcassets/Images/reviewStar.imageset/reviewStar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/NetworkService/DefaultNetworkService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkService.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultNetworkService: NetworkService { 14 | 15 | // MARK: - Properties 16 | private let session: URLSession = .shared 17 | 18 | // MARK: - Initializers 19 | 20 | // MARK: - Methods 21 | 22 | func request(_ endpoint: Endpoint) -> Observable { 23 | guard let urlRequest = endpoint.toURLRequest() else { return .error(NetworkError.invalidURL) } 24 | 25 | return URLSession.shared.rx 26 | .data(request: urlRequest) 27 | .asObservable() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/OpenSourceInfoDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenSourceInfoDTO.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct OpenSourceInfoDTO: Decodable { 12 | let identity: String 13 | let kind: String 14 | let location: String 15 | let state: State 16 | 17 | struct State: Decodable { 18 | let revision: String 19 | let version: String? 20 | let branch: String? 21 | } 22 | 23 | func toModel() -> OpenSourceInfo { 24 | return OpenSourceInfo( 25 | name: self.identity, 26 | version: self.state.version ?? self.state.branch ?? "master", 27 | url: URL(string: self.location) 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/LocationShare/DefaultUpdateLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultUpdateLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultUpdateLocationUseCase: UpdateLocationUseCase { 12 | 13 | // MARK: - Properties 14 | private let locationRepository: LocationRepository 15 | 16 | // MARK: - Initializers 17 | init(locationRepository: LocationRepository) { 18 | self.locationRepository = locationRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatroomId: String, location: Coordinate) -> Observable { 23 | return locationRepository.update(chatroomId: chatroomId, location: location) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/UserDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDTO.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct UserDTO: Codable { 12 | 13 | // MARK: - Properties 14 | let userId: String 15 | let nickname: String 16 | let profileImage: String 17 | let isPhotographer: Bool 18 | let fcmToken: String 19 | let status: User.Status 20 | 21 | // MARK: - Methods 22 | func toModel() -> User { 23 | return User( 24 | userId: userId, 25 | nickname: nickname, 26 | profileImage: URL(string: profileImage), 27 | isPhotographer: isPhotographer, 28 | fcmToken: fcmToken, 29 | status: status 30 | ) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultUpdateIsCheckedUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultUpdateIsCheckedUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultUpdateIsCheckedUseCase: UpdateIsCheckedUseCase { 12 | 13 | // MARK: - Properties 14 | private let chatRepository: ChatRepository 15 | 16 | // MARK: - Initializers 17 | init(chatRepository: ChatRepository) { 18 | self.chatRepository = chatRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatroomId: String, chatId: String, toState state: Bool) -> Observable { 23 | return chatRepository.updateIsChecked(chatroomId: chatroomId, chatId: chatId, toState: state) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Contact/CreateContactUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreateContactUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/06. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol CreateContactUseCase { 14 | func create(title: String, contents: String) -> Observable 15 | } 16 | 17 | final class DefaultCreateContactUseCase: CreateContactUseCase { 18 | 19 | private let userRepository: UserRepository 20 | 21 | init(userRepository: UserRepository) { 22 | self.userRepository = userRepository 23 | } 24 | 25 | func create(title: String, contents: String) -> Observable { 26 | return userRepository.createContact(title: title, contents: contents) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/ChatroomDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatroomDTO.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ChatroomDTO: Codable { 12 | 13 | // MARK: - Properties 14 | let chatroomId: String 15 | let customerUserId: String 16 | let photographerUserId: String 17 | let status: Chatroom.Status 18 | let updatedAt: String 19 | 20 | // MARK: - Methods 21 | func toModel() -> Chatroom { 22 | return Chatroom( 23 | chatroomId: chatroomId, 24 | customerUserId: customerUserId, 25 | photographerUserId: photographerUserId, 26 | status: status, 27 | updatedAt: Date.fromStringOrNow(updatedAt) 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Sue/DefaultCreateSueUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCreateSueUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/07. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultCreateSueUseCase: CreateSueUseCase { 14 | 15 | // MARK: Properties 16 | private let sueRepository: SueRepository 17 | 18 | // MARK: Initializers 19 | init(sueRepository: SueRepository) { 20 | self.sueRepository = sueRepository 21 | } 22 | 23 | // MARK: Methods 24 | func create(suedUserId: String, contents: Sue.SueContents) -> Observable { 25 | return sueRepository.sueUser(suedUserId: suedUserId, contents: contents.contents) 26 | .asObservable() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/Location/TrinapAnnotationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrinapAnnotationView.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/25. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import MapKit 10 | 11 | final class TrinapAnnotationView: MKAnnotationView, MKAnnotation { 12 | 13 | // MARK: - Properties 14 | dynamic var coordinate = CLLocationCoordinate2D() 15 | var isMine = true 16 | 17 | // MARK: - Initializers 18 | override init(annotation: MKAnnotation?, reuseIdentifier: String?) { 19 | super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | // MARK: - Methods 27 | } 28 | -------------------------------------------------------------------------------- /Queenfisher/Sources/ImageCache/ImageCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCache.swift 3 | // Queenfisher 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public final class ImageCache { 12 | 13 | // MARK: - Properties 14 | private static let shared = ImageCache() 15 | 16 | private let hybridImageCache: DefaultImageCache 17 | 18 | // MARK: Initializers 19 | init(performance: ConfigType = .normal) { 20 | hybridImageCache = DefaultImageCache(configType: performance) 21 | } 22 | 23 | // MARK: - Methods 24 | public static func instance(performance: ConfigType = .normal) -> ImageCacheProtocol { 25 | self.shared.hybridImageCache.config(performance) 26 | return self.shared.hybridImageCache 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Search/DefaultSearchLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultSearchLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import MapKit 10 | import Foundation 11 | 12 | import RxSwift 13 | import RxRelay 14 | 15 | final class DefaultSearchLocationUseCase: SearchLocationUseCase { 16 | 17 | // MARK: Properties 18 | private let mapService: MapRepository 19 | 20 | // MARK: Initializers 21 | init(mapService: MapRepository) { 22 | self.mapService = mapService 23 | } 24 | 25 | // MARK: Methods 26 | func fetchSearchList(with searchText: String) -> Observable<[Space]> { 27 | mapService.setSearchText(with: searchText) 28 | return mapService.results.asObservable() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/UITableView+Reusable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+Reusable.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UITableView { 12 | 13 | func register(_ cellClass: T.Type) where T: UITableViewCell { 14 | self.register(cellClass.self, forCellReuseIdentifier: cellClass.reuseIdentifier) 15 | } 16 | 17 | func dequeueCell(_ cellClass: T.Type, for indexPath: IndexPath) -> T? where T: UITableViewCell { 18 | return self.dequeueReusableCell(withIdentifier: cellClass.reuseIdentifier, for: indexPath) as? T 19 | } 20 | } 21 | 22 | extension UITableViewCell { 23 | 24 | static var reuseIdentifier: String { 25 | return String(describing: Self.self) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/ReviewDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewDTO.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ReviewDTO: Codable { 12 | 13 | // MARK: - Properties 14 | let creatorUserId, photographerUserId, reviewId, contents, status: String 15 | let createdAt: String 16 | let rating: Int 17 | 18 | // MARK: - Methods 19 | func toModel() -> Review { 20 | return Review( 21 | reviewId: reviewId, 22 | photographerUserId: photographerUserId, 23 | creatorUserId: creatorUserId, 24 | contents: contents, 25 | status: status, 26 | createdAt: Date.fromStringOrNow(createdAt), 27 | rating: rating 28 | ) 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Scripts/UpdatePackageRunScript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Open Source List && Output File Path 4 | openSourceList="Tuist/Dependencies/Lockfiles/Package.resolved" 5 | outputFilePath="Trinap/Resources/OpenSourceList.json" 6 | 7 | pwd 8 | 9 | # Check File Exists 10 | if [ ! -e $openSourceList ] 11 | then 12 | echo "Package.resolved not exists." 13 | exit -1 14 | fi 15 | 16 | # Parse to String 17 | json="`cat ${openSourceList}`" 18 | 19 | # Remove first 2 lines 20 | json=`echo "${json}" | sed -e '1,2d'` 21 | 22 | # Remove last 3 lines 23 | lineCount=`echo "${json}" | wc -l` 24 | json=`echo "${json}" | sed -e "$((lineCount-2)),$((lineCount))d"` 25 | 26 | # Configure as Array 27 | json=`echo "[\n${json}\n]"` 28 | 29 | # Create file if not exists 30 | if [ ! -e $outputFilePath ] 31 | then 32 | touch $outputFilePath 33 | fi 34 | 35 | # Put contents 36 | echo "${json}" > $outputFilePath -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Reservation/Detail/HandleStatus/ReservationError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationError.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | struct ReservationError: ReservationStatusConvertible, ReservationUseCaseExecutable { 12 | 13 | private typealias Configurations = ReservationStatusConfigurations 14 | private typealias Configuration = ReservationStatusConfigurations.Configuration 15 | 16 | func convert() -> ReservationStatusConfigurations { 17 | return Configurations( 18 | status: Configuration(title: "오류 발생", fillType: .fill, style: .secondary), 19 | primary: Configuration(title: "오류가 발생하였습니다.", fillType: .fill, style: .disabled), 20 | secondary: nil 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Chat/Chat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Chat.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Chat { 12 | 13 | enum ChatType: String, Codable { 14 | case text 15 | case image 16 | case reservation 17 | case location 18 | } 19 | 20 | enum SenderType { 21 | case mine 22 | case other 23 | } 24 | 25 | // MARK: - Properties 26 | let chatId: String 27 | let senderUserId: String 28 | let senderType: SenderType 29 | let chatType: ChatType 30 | let content: String 31 | let isChecked: Bool 32 | let createdAt: Date 33 | let imageWidth: Double? 34 | let imageHeight: Double? 35 | 36 | var user: User? 37 | } 38 | 39 | extension Chat: Hashable {} 40 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultSendFirstChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultSendFirstChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/05. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultSendFirstChatUseCase: SendFirstChatUseCase { 14 | 15 | // MARK: Properties 16 | private let chatRepository: ChatRepository 17 | 18 | // MARK: Initializers 19 | init(chatRepository: ChatRepository) { 20 | self.chatRepository = chatRepository 21 | } 22 | 23 | // MARK: Methods 24 | func send(chatroomId: String, reservationId: String) -> Observable { 25 | return chatRepository.send( 26 | chatType: .reservation, 27 | content: reservationId, 28 | at: chatroomId 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Repositories/Fake/FakeUploadImageRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FakeUploadImageRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | #if DEBUG 14 | struct FakeUploadImageRepository: UploadImageRepository, FakeRepositoryType { 15 | 16 | // MARK: - Properties 17 | var isSucceedCase: Bool 18 | 19 | // MARK: - Initializers 20 | init(isSucceedCase: Bool = FakeRepositoryEnvironment.isSucceedCase) { 21 | self.isSucceedCase = isSucceedCase 22 | } 23 | 24 | // MARK: - Methods 25 | func upload(image data: Data) -> Observable { 26 | return execute(successValue: "https://user-images.githubusercontent.com/27603734/200277055-fd64e53e-9901-4e8b-893a-1c028264500e.png") 27 | } 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Repositories/Image/DefaultUploadImageRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultUploadImageRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import FirestoreService 12 | import RxSwift 13 | 14 | final class DefaultUploadImageRepository: UploadImageRepository { 15 | 16 | // MARK: - Properties 17 | private let firestoreService: FireStoreService 18 | 19 | // MARK: - Initializers 20 | init(firestoreService: FireStoreService = DefaultFireStoreService()) { 21 | self.firestoreService = firestoreService 22 | } 23 | 24 | // MARK: - Methods 25 | func upload(image data: Data) -> Observable { 26 | return self.firestoreService 27 | .uploadImage(imageData: data) 28 | .asObservable() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/Cell/ReservationChatCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationChatCell.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class ReservationChatCell: ActionChatCell { 12 | 13 | // MARK: - Properties 14 | 15 | // MARK: - Initializers 16 | 17 | // MARK: - Methods 18 | override func configureCell(by chat: Chat, hasMyChatBefore: Bool, completion: (() -> Void)? = nil) { 19 | super.configureCell(by: chat, hasMyChatBefore: hasMyChatBefore, completion: completion) 20 | 21 | guard let user = chat.user else { return } 22 | 23 | self.contentLabel.text = "\(user.nickname) 님이 예약을 요청했습니다." 24 | self.actionButton.style = .secondary 25 | self.actionButton.setTitle("예약 확인", for: .normal) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/DefaultFetchReservationUserTypeUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultFetchReservationUserTypeUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/02. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DefaultFetchReservationUserTypeUseCase: FetchReservationUserTypeUseCase { 12 | 13 | // MARK: - Properties 14 | private let reservationRepository: ReservationRepository 15 | 16 | // MARK: - Initializers 17 | init(reservationRepository: ReservationRepository) { 18 | self.reservationRepository = reservationRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(customerId: String, photographerId: String) -> Reservation.UserType? { 23 | return reservationRepository.fetchUserType(customerId: customerId, photographerId: photographerId) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/Cell/LocationShareChatCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationShareChatCell.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class LocationShareChatCell: ActionChatCell { 12 | 13 | // MARK: - Properties 14 | 15 | // MARK: - Initializers 16 | 17 | // MARK: - Methods 18 | override func configureCell(by chat: Chat, hasMyChatBefore: Bool, completion: (() -> Void)? = nil) { 19 | super.configureCell(by: chat, hasMyChatBefore: hasMyChatBefore, completion: completion) 20 | 21 | guard let user = chat.user else { return } 22 | 23 | self.contentLabel.text = "\(user.nickname) 님이 위치 공유를 요청했습니다." 24 | self.actionButton.style = .black 25 | self.actionButton.setTitle("위치 공유하기", for: .normal) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/Array+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Array+.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Array { 12 | subscript (safe index: Array.Index) -> Element? { 13 | get { 14 | return indices ~= index ? self[index] : nil 15 | } 16 | set { 17 | guard let element = newValue else { return } 18 | self[index] = element 19 | } 20 | } 21 | } 22 | 23 | extension Array where Element: Hashable { 24 | func removingDuplicates() -> [Element] { 25 | var addedDict: [Element: Bool] = [:] 26 | 27 | return filter { 28 | addedDict.updateValue(true, forKey: $0) == nil 29 | } 30 | } 31 | 32 | mutating func removeDuplicates() { 33 | self = self.removingDuplicates() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Auth/AuthRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AuthRepository.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import FirebaseAuth 12 | import RxSwift 13 | 14 | 15 | protocol AuthRepository { 16 | 17 | // MARK: - Methods 18 | func checkUser() -> Single 19 | func createUser(nickname: String) -> Observable 20 | func updateFcmToken() -> Observable 21 | func deleteFcmToken() -> Observable 22 | func signIn(with cretencial: OAuthCredential) -> Single 23 | func signOut() -> Single 24 | func dropOut() -> Single 25 | func removeUserInfo(photographerId: String) -> Single 26 | func fetchRefreshToken(with authorizationCode: String) -> Observable 27 | func revokeToken() -> Observable 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/TokenManager/TokenManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenManager.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | typealias Token = String 12 | 13 | protocol TokenManager { 14 | 15 | /// `TokenManager`에 `key`로 저장되어 있는 토큰을 반환합니다. 16 | /// - Returns: 토큰이 저장되어 있으면 토큰을, 없으면 `nil`을 반환합니다. 17 | func getToken(with key: KeychainAccount) -> Token? 18 | 19 | /// `TokenManager`에 `key`에 해당하는 토큰을 저장 및 업데이트합니다. 20 | /// - Returns: 토큰 저장에 성공하면 `true`를, 실패하면 `false`를 반환합니다. 21 | @discardableResult 22 | func save(token: Token, with key: KeychainAccount) -> Bool 23 | 24 | /// `TokenManager`에서 `key`에 해당하는 토큰을 삭제합니다. 25 | /// - Returns: 토큰이 존재하지 않거나 삭제에 성공한 경우 `true`를, 실패하면 `false`를 반환합니다. 26 | @discardableResult 27 | func deleteToken(with key: KeychainAccount) -> Bool 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/Custom/UnreadAccessoryView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnreadAccessoryView.swift 3 | // TrinapTests 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import SnapKit 12 | 13 | final class UnreadAccessoryView: BaseView { 14 | 15 | // MARK: - Properties 16 | var side: CGFloat 17 | 18 | // MARK: - Initializer 19 | init(side: CGFloat = 8.0) { 20 | self.side = side 21 | 22 | super.init(frame: .zero) 23 | 24 | self.clipsToBounds = true 25 | self.layer.cornerRadius = side / 2 26 | self.backgroundColor = TrinapAsset.primary.color 27 | } 28 | 29 | override func configureConstraints() { 30 | self.snp.makeConstraints { make in 31 | make.width.equalTo(side) 32 | make.height.equalTo(side) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/MKAnnotationView+Reusable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MKAnnotationView+Reusable.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/25. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import MapKit 10 | 11 | extension MKMapView { 12 | 13 | func register(_ annotationViewClass: T.Type) where T: MKAnnotationView { 14 | self.register( 15 | annotationViewClass.self, 16 | forAnnotationViewWithReuseIdentifier: annotationViewClass.reuseIdentifier 17 | ) 18 | } 19 | 20 | func dequeueAnnotationView(_ annotationViewClass: T.Type) -> T? where T: MKAnnotationView { 21 | return self.dequeueReusableAnnotationView(withIdentifier: T.reuseIdentifier) as? T 22 | } 23 | } 24 | 25 | extension MKAnnotationView { 26 | 27 | static var reuseIdentifier: String { 28 | return String(describing: Self.self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/MyPage/MyPage/Tableview/MyPageSectionHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyPageSectionHeader.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class MyPageSectionHeader: BaseView { 12 | 13 | private lazy var titleLabel = UILabel().than { 14 | $0.text = "작가 설정" 15 | $0.font = TrinapFontFamily.Pretendard.bold.font(size: 16) 16 | } 17 | 18 | override func configureHierarchy() { 19 | self.addSubview(titleLabel) 20 | } 21 | 22 | override func configureConstraints() { 23 | titleLabel.snp.makeConstraints { make in 24 | make.centerY.equalToSuperview() 25 | make.leading.equalTo(self.trinapOffset * 2) 26 | } 27 | } 28 | 29 | func configure(with title: String) { 30 | self.titleLabel.text = title 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Trinap/Sources/App/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/14. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | var appCoordinator: AppCoordinator? 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | guard let windowScene = (scene as? UIWindowScene) else { return } 18 | window = UIWindow(windowScene: windowScene) 19 | 20 | let navigationController = UINavigationController() 21 | appCoordinator = AppCoordinator(navigationController) 22 | 23 | window?.rootViewController = navigationController 24 | window?.makeKeyAndVisible() 25 | 26 | appCoordinator?.start() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Base/BaseView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseView.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RxSwift 11 | 12 | class BaseView: UIView { 13 | 14 | // MARK: - Properties 15 | var disposeBag = DisposeBag() 16 | 17 | // MARK: - Methods 18 | override init(frame: CGRect) { 19 | super.init(frame: frame) 20 | 21 | self.backgroundColor = TrinapAsset.white.color 22 | configureAttributes() 23 | configureHierarchy() 24 | configureConstraints() 25 | bind() 26 | } 27 | 28 | func configureHierarchy() {} 29 | func configureConstraints() {} 30 | func configureAttributes() {} 31 | func bind() {} 32 | 33 | @available(*, unavailable) 34 | required init?(coder: NSCoder) { 35 | fatalError("init(coder:) is called.") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Main/SelectReservationDate/TitleSectionHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TitleSectionHeaderView.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/24. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import SnapKit 12 | import Than 13 | 14 | final class TitleSectionHeaderView: BaseCollectionReusableView { 15 | private lazy var titleLabel = UILabel().than { 16 | $0.font = TrinapFontFamily.Pretendard.bold.font(size: 16) 17 | $0.textColor = TrinapAsset.black.color 18 | } 19 | 20 | override func configureHierarchy() { 21 | self.addSubview(titleLabel) 22 | } 23 | 24 | override func configureConstraints() { 25 | titleLabel.snp.makeConstraints { make in 26 | make.edges.equalToSuperview() 27 | } 28 | } 29 | 30 | func configureHeaderView(title: String) { 31 | self.titleLabel.text = title 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Base/BaseCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseCollectionViewCell.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import RxSwift 12 | import RxCocoa 13 | 14 | class BaseCollectionViewCell: UICollectionViewCell { 15 | 16 | // MARK: - Properties 17 | var disposeBag = DisposeBag() 18 | 19 | // MARK: - Methods 20 | override init(frame: CGRect) { 21 | super.init(frame: frame) 22 | 23 | configureAttributes() 24 | configureHierarchy() 25 | configureConstraints() 26 | bind() 27 | } 28 | 29 | func configureHierarchy() {} 30 | func configureConstraints() {} 31 | func configureAttributes() {} 32 | func bind() {} 33 | 34 | @available(*, unavailable) 35 | required init?(coder: NSCoder) { 36 | fatalError("init(coder:) is called.") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Reservation/ReservationRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationRepository.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol ReservationRepository { 14 | 15 | // MARK: Methods 16 | func fetchUserType(customerId: String, photographerId: String) -> Reservation.UserType? 17 | func fetchReceivedReservations() -> Observable<[Reservation.Mapper]> 18 | func fetchSentReservations() -> Observable<[Reservation.Mapper]> 19 | func create( 20 | photographerUserId: String, 21 | startDate: Date, 22 | endDate: Date, 23 | coordinate: Coordinate 24 | ) -> Observable 25 | func fetchReservation(reservationId: String) -> Observable 26 | func updateReservationStatus(reservationId: String, status: Reservation.Status) -> Observable 27 | } 28 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Contact/FetchContactUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FetchContactUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/06. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol FetchContactUseCase { 14 | func fetchContacts() -> Observable<[Contact]> 15 | func fetchDetailContact(contactId: String) -> Observable 16 | } 17 | 18 | final class DefaultFetchContactUseCase: FetchContactUseCase { 19 | 20 | private let userRepository: UserRepository 21 | 22 | init(userRepository: UserRepository) { 23 | self.userRepository = userRepository 24 | } 25 | 26 | func fetchContacts() -> Observable<[Contact]> { 27 | return userRepository.fetchContact() 28 | } 29 | 30 | func fetchDetailContact(contactId: String) -> Observable { 31 | return userRepository.fetchDetailContact(contactId: contactId) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Base/BaseCollectionReusableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseCollectionReusableView.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import RxSwift 12 | import RxCocoa 13 | 14 | class BaseCollectionReusableView: UICollectionReusableView { 15 | 16 | // MARK: - Properties 17 | var disposeBag = DisposeBag() 18 | 19 | // MARK: - Methods 20 | override init(frame: CGRect) { 21 | super.init(frame: frame) 22 | 23 | configureAttributes() 24 | configureHierarchy() 25 | configureConstraints() 26 | bind() 27 | } 28 | 29 | func configureHierarchy() {} 30 | func configureConstraints() {} 31 | func configureAttributes() {} 32 | func bind() {} 33 | 34 | @available(*, unavailable) 35 | required init?(coder: NSCoder) { 36 | fatalError("init(coder:) is called.") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Review/DefaultCreateReviewUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCreateReviewUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/18. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import FirestoreService 12 | import RxSwift 13 | 14 | final class DefaultCreateReviewUseCase: CreateReviewUseCase { 15 | 16 | private let reviewRepository: ReviewRepository 17 | 18 | init(reviewRepository: ReviewRepository) { 19 | self.reviewRepository = reviewRepository 20 | } 21 | 22 | func createReview(photographerId: String, contents: String, rating: Int) -> Observable { 23 | return reviewRepository.createReview(to: photographerId, contents: contents, rating: rating) 24 | .asObservable() 25 | } 26 | 27 | func checkButtonEnabled(text: String, rating: Int) -> Bool { 28 | return text != "작가님을 위한 한마디를 남겨주세요!" && !text.isEmpty && rating != 0 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/User/UserRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol UserRepository { 14 | 15 | // MARK: - Methods 16 | func fetch() -> Observable 17 | func fetch(userId: String) -> Observable 18 | func fetchUsers(userIds: [String]) -> Observable<[User]> 19 | func fetchUsersWithMine(userIds: [String]) -> Observable<[User]> 20 | func update(profileImage: String?, nickname: String?, isPhotographer: Bool?) -> Observable 21 | func createRandomNickname() -> Observable 22 | func updatePhotographerExposure(value: Bool) -> Observable 23 | func fetchContact() -> Observable<[Contact]> 24 | func fetchDetailContact(contactId: String) -> Observable 25 | func createContact(title: String, contents: String) -> Observable 26 | } 27 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Auth/SignOut/DefaultSignOutUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultSignOutUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultSignOutUseCase: SignOutUseCase { 14 | 15 | // MARK: - Properties 16 | private let authRepository: AuthRepository 17 | 18 | // MARK: - Initializers 19 | init(authRepository: AuthRepository) { 20 | self.authRepository = authRepository 21 | } 22 | 23 | // MARK: - Methods 24 | func signOut() -> Observable { 25 | return self.authRepository.deleteFcmToken() 26 | .withUnretained(self) 27 | .flatMap { owner, _ -> Single in 28 | return owner.authRepository.signOut() 29 | } 30 | .asObservable() 31 | .map { true } 32 | .catchAndReturn(false) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Reservation/Detail/HandleStatus/ReservationStatusConfigurations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReservationStatusConfigurations.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/02. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ReservationStatusConfigurations { 12 | 13 | let status: Configuration 14 | let primary: Configuration? 15 | let secondary: Configuration? 16 | 17 | static var onError: Self { 18 | return Self( 19 | status: Configuration(title: "오류", fillType: .fill, style: .error), 20 | primary: Configuration(title: "오류가 발생했습니다.", fillType: .fill, style: .disabled), 21 | secondary: nil 22 | ) 23 | } 24 | } 25 | 26 | extension ReservationStatusConfigurations { 27 | 28 | struct Configuration { 29 | 30 | let title: String 31 | let fillType: TrinapButton.FillType 32 | let style: TrinapButton.ColorType 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Block/DefaultCreateBlockUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCreateBlockUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/03. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultCreateBlockUseCase: CreateBlockUseCase { 14 | 15 | // MARK: Properties 16 | private let blockRepository: BlockRepository 17 | 18 | // MARK: Initializers 19 | init(blockRepository: BlockRepository) { 20 | self.blockRepository = blockRepository 21 | } 22 | 23 | // MARK: Methods 24 | func create(blockedUserId: String) -> Single { 25 | return blockRepository.blockUser(blockedUserId: blockedUserId) 26 | } 27 | 28 | func create(blockedUserId: String, blockId: String) -> Single { 29 | return self.blockRepository.blockUser( 30 | blockedUserId: blockedUserId, 31 | blockId: blockId 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Photographer/DefaultFetchPhotographerUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultFetchPhotographerUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultFetchPhotographerUseCase: FetchPhotographerUseCase { 14 | 15 | // MARK: Properties 16 | private let photographerRespository: PhotographerRepository 17 | 18 | // MARK: Initializer 19 | init(photographerRespository: PhotographerRepository) { 20 | self.photographerRespository = photographerRespository 21 | } 22 | 23 | // MARK: Methods 24 | func fetch(photographerUserId: String?) -> Observable { 25 | guard let photographerUserId else { 26 | return photographerRespository.fetchDetailPhotographer() 27 | } 28 | return photographerRespository.fetchDetailPhotographer(userId: photographerUserId) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Repositories/OpenSource/DefaultOpenSourceListRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultOpenSourceListRepository.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DefaultOpenSourceListRepository: OpenSourceListRepository { 12 | 13 | // MARK: - Methods 14 | func fetchOpenSourceList() -> [OpenSourceInfo] { 15 | guard let path = Bundle.main.path(forResource: "OpenSourceList", ofType: "json") else { 16 | return [] 17 | } 18 | let url = URL(fileURLWithPath: path) 19 | 20 | do { 21 | let data = try Data(contentsOf: url) 22 | let openSourceList = try JSONDecoder().decode([OpenSourceInfoDTO].self, from: data) 23 | return openSourceList.map { $0.toModel() } 24 | } catch let error { 25 | print("Json Decode Error: \(error.localizedDescription)") 26 | return [] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Main/PhotographerDetail/PhotographerDetailDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotographerDetailDataSource.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SkeletonView 11 | 12 | class PhotographerListSkeletonDiffableDataSource: 13 | UICollectionViewDiffableDataSource { 14 | 15 | override init(collectionView: UICollectionView, cellProvider: @escaping UICollectionViewDiffableDataSource.CellProvider) { 16 | super.init(collectionView: collectionView, cellProvider: cellProvider) 17 | } 18 | } 19 | 20 | extension PhotographerListSkeletonDiffableDataSource: SkeletonCollectionViewDataSource { 21 | 22 | func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier { 23 | return PhotographerPreviewCell.reuseIdentifier 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/UIViewController+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIViewController { 12 | 13 | /// offset 기본 단위 14 | var trinapOffset: CGFloat { 15 | return UIScreen.main.bounds.width / 50 16 | } 17 | 18 | func hideKeyboardWhenTapped() { 19 | let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) 20 | tap.cancelsTouchesInView = false 21 | // 기본값이 true이면 제스쳐 발동시 터치 이벤트가 뷰로 전달x 22 | // 즉 제스쳐가 동작하면 뷰의 터치이벤트는 발생하지 않는것 false면 둘 다 작동한다는 뜻 23 | view.addGestureRecognizer(tap) 24 | } 25 | 26 | @objc func dismissKeyboard() { 27 | self.view.endEditing(true) 28 | } 29 | } 30 | 31 | extension UIView { 32 | 33 | /// offset 기본 단위 34 | var trinapOffset: CGFloat { 35 | return UIScreen.main.bounds.width / 50 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/MyPage/DefaultEditUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultEditUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultEditUserUseCase: EditUserUseCase { 14 | 15 | private let userRepository: UserRepository 16 | 17 | init(userRepository: UserRepository) { 18 | self.userRepository = userRepository 19 | } 20 | 21 | func updateProfielInfo(profileImage: String?, nickName: String?) -> Observable { 22 | return userRepository.update(profileImage: profileImage, nickname: nickName, isPhotographer: nil) 23 | } 24 | 25 | func fetchRandomNickName() -> Observable { 26 | return userRepository.createRandomNickname() 27 | } 28 | 29 | func updatePhotographerExposure(_ isOn: Bool) -> Observable { 30 | return userRepository.updatePhotographerExposure(value: isOn) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/DefaultCompletePhotoshootUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCompletePhotoshootUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultCompletePhotoshootUseCase: CompletePhotoshootUseCase { 12 | 13 | // MARK: - Properties 14 | private let repository: ReservationRepository 15 | 16 | // MARK: - Initializers 17 | init(repository: ReservationRepository) { 18 | self.repository = repository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(reservation: Reservation) -> Observable { 23 | return repository.updateReservationStatus(reservationId: reservation.reservationId, status: .done) 24 | .map { _ in 25 | var mutableReservation = reservation 26 | 27 | mutableReservation.status = .done 28 | return mutableReservation 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/ChatDetail/ChatTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatTableView.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class ChatTableView: UITableView { 12 | 13 | // MARK: - Properties 14 | 15 | // MARK: - Initializers 16 | init() { 17 | super.init(frame: .zero, style: .plain) 18 | 19 | self.separatorStyle = .none 20 | self.allowsSelection = false 21 | self.register() 22 | } 23 | 24 | required init?(coder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | // MARK: - Methods 29 | private func register() { 30 | self.register(ChatCell.self) 31 | self.register(TextChatCell.self) 32 | self.register(ImageChatCell.self) 33 | self.register(ActionChatCell.self) 34 | self.register(ReservationChatCell.self) 35 | self.register(LocationShareChatCell.self) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/DefaultAcceptReservationRequestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultAcceptReservationRequestUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultAcceptReservationRequestUseCase: AcceptReservationRequestUseCase { 12 | 13 | // MARK: - Properties 14 | private let repository: ReservationRepository 15 | 16 | // MARK: - Initializers 17 | init(repository: ReservationRepository) { 18 | self.repository = repository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(reservation: Reservation) -> Observable { 23 | return repository.updateReservationStatus(reservationId: reservation.reservationId, status: .confirm) 24 | .map { _ in 25 | var mutableReservation = reservation 26 | 27 | mutableReservation.status = .confirm 28 | return mutableReservation 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/DefaultCancelReservationRequestUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCancelReservationRequestUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/04. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultCancelReservationRequestUseCase: CancelReservationRequestUseCase { 12 | 13 | // MARK: - Properties 14 | private let repository: ReservationRepository 15 | 16 | // MARK: - Initializers 17 | init(repository: ReservationRepository) { 18 | self.repository = repository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(reservation: Reservation) -> Observable { 23 | return repository.updateReservationStatus(reservationId: reservation.reservationId, status: .cancel) 24 | .map { _ in 25 | var mutableReservation = reservation 26 | 27 | mutableReservation.status = .cancel 28 | return mutableReservation 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Search/DefaultFetchCurrentLocationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultFetchCurrentLocationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/29. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultFetchCurrentLocationUseCase: FetchCurrentLocationUseCase { 14 | 15 | // MARK: Properties 16 | private let mapRepository: MapRepository 17 | 18 | // MARK: Initializers 19 | init(mapRepository: MapRepository) { 20 | self.mapRepository = mapRepository 21 | } 22 | 23 | // MARK: Methods 24 | func fetchCurrentLocation() -> Observable<(Coordinate, String)> { 25 | let result = mapRepository.fetchCurrentLocation() 26 | var coor = Coordinate.seoulCoordinate 27 | 28 | if case let .success(success) = result { 29 | coor = success 30 | } 31 | 32 | return mapRepository.fetchLocationName(using: coor) 33 | .map { (coor, $0) } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/Date+ProperText.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date+ProperText.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/18. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Date { 12 | 13 | var properText: String { 14 | let calendar = Calendar.current 15 | 16 | if calendar.isDateInToday(self) { 17 | return self.toString(type: .hourAndMinute) 18 | } else if calendar.isDateInYesterday(self) { 19 | return "어제" 20 | } else if self.isDateInCurrentYear() { 21 | return self.toString(type: .monthAndDate) 22 | } else { 23 | return self.toString(type: .yearAndMonthAndDate) 24 | } 25 | } 26 | 27 | private func isDateInCurrentYear() -> Bool { 28 | let calendar = Calendar.current 29 | let currentYear = calendar.component(.year, from: Date()) 30 | let year = calendar.component(.year, from: self) 31 | 32 | return currentYear == year 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/MyPage/Photographer/ColletionView/EditPhotographerPhotoHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EditPhotographerPhotoHeaderView.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/24. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import RxSwift 12 | import RxCocoa 13 | 14 | final class EditPhotographerPhotoHeaderView: BaseCollectionReusableView { 15 | lazy var editButton = TrinapButton(style: .black, fillType: .border, isCircle: true) 16 | 17 | override func prepareForReuse() { 18 | super.prepareForReuse() 19 | 20 | self.disposeBag = DisposeBag() 21 | } 22 | 23 | override func configureHierarchy() { 24 | self.addSubview(editButton) 25 | } 26 | 27 | override func configureConstraints() { 28 | editButton.snp.makeConstraints { make in 29 | make.edges.equalToSuperview() 30 | } 31 | } 32 | 33 | override func configureAttributes() { 34 | editButton.setTitle("포트폴리오 편집", for: .normal) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/UIAlertController+Builder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIAlertController+Rx.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIAlertController { 12 | 13 | /// 파라미터를 기반으로 `UIAlertController`에 `UIAlertAction`을 추가한 후 반환합니다. 14 | /// 15 | /// 사용법 16 | /// ``` 17 | /// let alertController = UIAlertController(...) 18 | /// .appendingAction(...) 19 | /// .appendingAction(...) 20 | /// .appendingAction(...) 21 | /// ``` 22 | func appendingAction( 23 | title: String?, 24 | style: UIAlertAction.Style = .default, 25 | handler: (() -> Void)? = nil 26 | ) -> Self { 27 | let alertAction = UIAlertAction(title: title, style: style) { _ in handler?() } 28 | 29 | self.addAction(alertAction) 30 | return self 31 | } 32 | 33 | func appendingCancel() -> Self { 34 | return self.appendingAction(title: "취소", style: .cancel) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Endpoint/TokenEndpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenEndpoint.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/06. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum TokenEndpoint: Endpoint { 12 | case refresh(authorizationCode: String) 13 | case revoke(refreshToken: String) 14 | 15 | var baseURL: URL? { 16 | return URL(string: "https://us-central1-trinapserver.cloudfunctions.net") 17 | } 18 | 19 | var method: HTTPMethod { return .GET } 20 | 21 | var path: String { 22 | switch self { 23 | case .refresh: 24 | return "getRefreshToken" 25 | case .revoke: 26 | return "revokeToken" 27 | } 28 | } 29 | 30 | var parameters: HTTPRequestParameter? { 31 | switch self { 32 | case .refresh(let authorizationCode): 33 | return .query(["code": authorizationCode]) 34 | case .revoke(let refreshToken): 35 | return .query(["refresh_token": refreshToken]) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Photographer/Photographer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Photographer.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Photographer { 12 | 13 | // MARK: - Properties 14 | let photographerId, photographerUserId: String 15 | let introduction: String? 16 | let latitude, longitude: Double 17 | let tags: [TagType] 18 | let pictures: [String] 19 | let pricePerHalfHour: Int? 20 | var possibleDate: [Date] 21 | 22 | // MARK: - Methods 23 | static func createDefaultPhotographer() -> Photographer { 24 | return Photographer( 25 | photographerId: UUID().uuidString, 26 | photographerUserId: "", 27 | introduction: nil, 28 | latitude: Coordinate.seoulCoordinate.lat, 29 | longitude: Coordinate.seoulCoordinate.lng, 30 | tags: [], 31 | pictures: [], 32 | pricePerHalfHour: nil, 33 | possibleDate: [] 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/BlockDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlockDTO.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct BlockDTO: Codable { 12 | 13 | // MARK: Properties 14 | let blockId: String 15 | let blockedUserId: String 16 | let userId: String 17 | let status: String 18 | 19 | init(blockId: String, blockedUserId: String, userId: String, status: String) { 20 | self.blockId = blockId 21 | self.blockedUserId = blockedUserId 22 | self.userId = userId 23 | self.status = status 24 | } 25 | 26 | init(block: Block, status: String) { 27 | self.blockId = block.blockId 28 | self.blockedUserId = block.blockedUserId 29 | self.userId = block.userId 30 | self.status = status 31 | } 32 | 33 | // MARK: Methods 34 | func toBlock() -> Block { 35 | return Block( 36 | blockId: blockId, 37 | blockedUserId: blockedUserId, 38 | userId: userId 39 | ) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Repositories/Photographer/PhotographerRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotographerRepository.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | protocol PhotographerRepository { 14 | 15 | // MARK: Methods 16 | func fetchPhotographers(type: TagType) -> Observable<[Photographer]> 17 | func fetchPhotographers(ids: [String]) -> Observable<[Photographer]> 18 | func fetchPhotographers(coordinate: Coordinate) -> Observable<[Photographer]> 19 | func fetchDetailPhotographer(of photograhperId: String) -> Observable 20 | func fetchDetailPhotographer(userId: String) -> Observable 21 | func fetchDetailPhotographer() -> Observable 22 | 23 | func create(photographer: Photographer) -> Observable 24 | func updatePhotograhperInformation(with information: Photographer) -> Observable 25 | func updatePortfolioPictures(photograhperId: String, with images: [String], image: Data) -> Observable 26 | } 27 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/MyPage/DefaultFetchUserUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultFetchUserUseCase.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/21. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultFetchUserUseCase: FetchUserUseCase { 14 | 15 | private let userRepository: UserRepository 16 | private let tokenManager: TokenManager 17 | 18 | init( 19 | userRepository: UserRepository, 20 | tokenManager: TokenManager = KeychainTokenManager() 21 | ) { 22 | self.userRepository = userRepository 23 | self.tokenManager = tokenManager 24 | } 25 | 26 | func fetchUserInfo() -> Observable { 27 | guard let token = tokenManager.getToken(with: .userId) else { 28 | return .error(TokenManagerError.notFound) 29 | } 30 | 31 | return userRepository.fetch(userId: token) 32 | } 33 | 34 | func fetchUserInfo(userId: String) -> Observable { 35 | return userRepository.fetch(userId: userId) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Reservation/DefaultCreateReservationUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCreateReservationUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/01. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultCreateReservationUseCase: CreateReservationUseCase { 14 | 15 | // MARK: Properties 16 | private let reservationRepository: ReservationRepository 17 | 18 | // MARK: Initializers 19 | init(reservationRepository: ReservationRepository) { 20 | self.reservationRepository = reservationRepository 21 | } 22 | 23 | // MARK: Methods 24 | func create( 25 | photographerUserId: String, 26 | startDate: Date, 27 | endDate: Date, 28 | coordinate: Coordinate 29 | ) -> Observable { 30 | 31 | reservationRepository.create( 32 | photographerUserId: photographerUserId, 33 | startDate: startDate, 34 | endDate: endDate, 35 | coordinate: coordinate 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Chat/Cell/ChatContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatContentView.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/20. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class ChatContentView: BaseView { 12 | 13 | // MARK: - Properties 14 | var sender: Chat.SenderType = .mine { 15 | didSet { applySenderType() } 16 | } 17 | 18 | // MARK: - Initializers 19 | init() { 20 | super.init(frame: .zero) 21 | 22 | applySenderType() 23 | self.clipsToBounds = true 24 | self.layer.cornerRadius = 8.0 25 | } 26 | 27 | // MARK: - Methods 28 | private func applySenderType() { 29 | self.backgroundColor = self.sender.backgroundColor 30 | } 31 | } 32 | 33 | // MARK: - SenderType 34 | private extension Chat.SenderType { 35 | 36 | var backgroundColor: UIColor { 37 | switch self { 38 | case .mine: 39 | return TrinapAsset.background.color 40 | case .other: 41 | return TrinapAsset.sub2.color 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ---- 3 | 4 | # Installation 5 | 6 | Make sure you have the latest version of the Xcode command line tools installed: 7 | 8 | ```sh 9 | xcode-select --install 10 | ``` 11 | 12 | For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) 13 | 14 | # Available Actions 15 | 16 | ## iOS 17 | 18 | ### ios local 19 | 20 | ```sh 21 | [bundle exec] fastlane ios local 22 | ``` 23 | 24 | Push a new beta build to TestFlight in local 25 | 26 | ### ios remote 27 | 28 | ```sh 29 | [bundle exec] fastlane ios remote 30 | ``` 31 | 32 | build app and upload to testflight in remote 33 | 34 | ### ios certificates 35 | 36 | ```sh 37 | [bundle exec] fastlane ios certificates 38 | ``` 39 | 40 | Get certificates 41 | 42 | ---- 43 | 44 | This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. 45 | 46 | More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). 47 | 48 | The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 49 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultSendChatUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultSendChatUseCase.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import RxSwift 10 | 11 | final class DefaultSendChatUseCase: SendChatUseCase { 12 | 13 | // MARK: - Properties 14 | private let chatRepository: ChatRepository 15 | 16 | // MARK: - Initializers 17 | init(chatRepository: ChatRepository) { 18 | self.chatRepository = chatRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func execute(chatType: Chat.ChatType, content: String, chatroomId: String) -> Observable { 23 | return chatRepository.send(chatType: chatType, content: content, at: chatroomId) 24 | } 25 | 26 | func execute(imageURL: String, chatroomId: String, imageWidth: Double, imageHeight: Double) -> Observable { 27 | return chatRepository.send( 28 | imageURL: imageURL, 29 | chatroomId: chatroomId, 30 | imageWidth: imageWidth, 31 | imageHeight: imageHeight 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tuist/Dependencies.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dependencies.swift 3 | // Config 4 | // 5 | // Created by 김세영 on 2022/11/10. 6 | // 7 | 8 | import ProjectDescription 9 | 10 | let spm = SwiftPackageManagerDependencies([ 11 | .remote(url: "https://github.com/ReactiveX/RxSwift", requirement: .upToNextMajor(from: "6.5.0")), 12 | .remote(url: "https://github.com/RxSwiftCommunity/RxGesture", requirement: .upToNextMinor(from: "4.0.0")), 13 | .remote(url: "https://github.com/firebase/firebase-ios-sdk", requirement: .upToNextMajor(from: "8.10.0")), 14 | .remote(url: "https://github.com/airbnb/lottie-ios", requirement: .branch("master")), 15 | .remote(url: "https://github.com/SnapKit/SnapKit", requirement: .upToNextMajor(from: "5.0.0")), 16 | .remote(url: "https://github.com/airbnb/HorizonCalendar.git", requirement: .branch("master")), 17 | .remote(url: "https://github.com/onevcat/Kingfisher", requirement: .upToNextMajor(from: "7.0")), 18 | .remote(url: "https://github.com/Juanpe/SkeletonView", requirement: .upToNextMajor(from: "1.7.0")) 19 | ]) 20 | 21 | let dependencies = Dependencies( 22 | swiftPackageManager: spm, 23 | platforms: [.iOS] 24 | ) 25 | -------------------------------------------------------------------------------- /Trinap/Sources/Utils/Logger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Logger { 12 | 13 | static func print(_ items: Any, file: String = #file, function: String = #function, line: Int = #line) { 14 | #if DEBUG 15 | Swift.print() 16 | Swift.print("🟢 Log at \(file.components(separatedBy: "/").last ?? "Some File")") 17 | Swift.print("🟢 function: \(function), line: \(line)") 18 | Swift.print("🟢") 19 | Swift.print("🟢", items) 20 | Swift.print() 21 | #endif 22 | } 23 | 24 | static func printArray(_ array: [Any], file: String = #file, function: String = #function, line: Int = #line) { 25 | #if DEBUG 26 | Swift.print() 27 | Swift.print("🟢 Log at \(file.components(separatedBy: "/").last ?? "Some File")") 28 | Swift.print("🟢 function: \(function), line: \(line)") 29 | Swift.print("🟢") 30 | for item in array { 31 | Swift.print("🟢", item) 32 | } 33 | Swift.print() 34 | #endif 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Chat/ChatPreview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatPreview.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ChatPreview { 12 | 13 | // MARK: - Properties 14 | let chatroomId: String 15 | let profileImage: URL? 16 | let nickname: String 17 | var chatType: Chat.ChatType 18 | var content: String 19 | var date: Date 20 | var isChecked: Bool 21 | } 22 | 23 | extension ChatPreview: Hashable { 24 | 25 | static var onError: Self { 26 | return ChatPreview( 27 | chatroomId: UUID().uuidString, 28 | profileImage: nil, 29 | nickname: "오류", 30 | chatType: .text, 31 | content: "오류가 발생했습니다.", 32 | date: Date(), 33 | isChecked: true 34 | ) 35 | } 36 | 37 | func hash(into hasher: inout Hasher) { 38 | hasher.combine(chatroomId) 39 | } 40 | } 41 | 42 | extension ChatPreview: Comparable { 43 | 44 | static func < (lhs: ChatPreview, rhs: ChatPreview) -> Bool { 45 | return lhs.date < rhs.date 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Reusable/PaddingLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PaddingLabel.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/23. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // 양 옆 패딩(마진)설정이 가능한 커스텀 레이블 12 | class PaddingLabel: UILabel { 13 | 14 | var top: CGFloat = 0 15 | var bottom: CGFloat = 0 16 | var left: CGFloat = 0 17 | var right: CGFloat = 0 18 | 19 | convenience init(padding: UIEdgeInsets) { 20 | self.init() 21 | self.top = padding.top 22 | self.left = padding.left 23 | self.bottom = padding.bottom 24 | self.right = padding.right 25 | } 26 | 27 | override func drawText(in rect: CGRect) { 28 | let padding = UIEdgeInsets.init(top: top, left: left, bottom: bottom, right: right) 29 | super.drawText(in: rect.inset(by: padding)) 30 | } 31 | 32 | override var intrinsicContentSize: CGSize { 33 | var contentSize = super.intrinsicContentSize 34 | contentSize.width += self.left + self.right 35 | contentSize.height += self.top + self.bottom 36 | 37 | return contentSize 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/Repositories/Fake/FakeMapRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FakeMapRepository.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/12. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | import RxRelay 13 | 14 | #if DEBUG 15 | struct FakeMapRepository: MapRepository, FakeRepositoryType { 16 | 17 | // MARK: - Properties 18 | let isSucceedCase: Bool 19 | 20 | let results = BehaviorRelay<[Space]>(value: []) 21 | 22 | // MARK: - Initializers 23 | init(isSucceedCase: Bool = FakeRepositoryEnvironment.isSucceedCase) { 24 | self.isSucceedCase = isSucceedCase 25 | } 26 | 27 | // MARK: - Methods 28 | func setSearchText(with searchText: String) {} 29 | 30 | func fetchCurrentLocation() -> Result { 31 | if isSucceedCase { 32 | return .success(.seoulCoordinate) 33 | } else { 34 | return .failure(FakeError.unknown) 35 | } 36 | } 37 | 38 | func fetchLocationName(using coordinate: Coordinate) -> Observable { 39 | return execute(successValue: "Location Name") 40 | } 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/Models/Filter/TagType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TagType.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 메인화면 필터, 작가의 프로필의 태그 설정할 때 사용 12 | enum TagType: String, CaseIterable { 13 | 14 | case all = "전체" 15 | case profile = "프로필 사진" 16 | case instagram = "인스타" 17 | case pet = "반려동물" 18 | case wedding = "웨딩 촬영" 19 | case filmCamera = "필카감성" 20 | 21 | var title: String { 22 | switch self { 23 | case .all: 24 | return "전체" 25 | case .profile: 26 | return "프로필 사진" 27 | case .instagram: 28 | return "인스타" 29 | case .pet: 30 | return "반려동물" 31 | case .wedding: 32 | return "웨딩 촬영" 33 | case .filmCamera: 34 | return "필카 감성" 35 | } 36 | } 37 | 38 | init(index: Int) { 39 | switch index { 40 | case 0: self = .all 41 | case 1: self = .profile 42 | case 2: self = .instagram 43 | case 3: self = .pet 44 | case 4: self = .wedding 45 | case 5: self = .filmCamera 46 | default: self = .all 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/OpenSource/DefaultFetchOpenSourceListUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultFetchOpenSourceListUseCase.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DefaultFetchOpenSourceListUseCase: FetchOpenSourceListUseCase { 12 | 13 | // MARK: - Properties 14 | let fetchOpenSourceListRepository: OpenSourceListRepository 15 | 16 | // MARK: - Initializers 17 | init(fetchOpenSourceListRepository: OpenSourceListRepository) { 18 | self.fetchOpenSourceListRepository = fetchOpenSourceListRepository 19 | } 20 | 21 | // MARK: - Methods 22 | func fetchOpenSource() -> [OpenSourceInfo] { 23 | return self.fetchOpenSourceListRepository.fetchOpenSourceList() 24 | .map { info in 25 | var mutableInfo = info 26 | 27 | mutableInfo.name = info.url?.absoluteString 28 | .components(separatedBy: "/") 29 | .last? 30 | .components(separatedBy: ".") 31 | .first ?? info.name 32 | 33 | return mutableInfo 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Queenfisher/Sources/General/Queenfisher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Queenfisher.swift 3 | // Queenfisher 4 | // 5 | // Created by 김세영 on 2022/11/15. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public typealias QFImage = UIImage 12 | public typealias QFImageView = UIImageView 13 | public typealias QFButton = UIButton 14 | public typealias QFIndicator = UIActivityIndicatorView 15 | public typealias QFData = Data 16 | 17 | /// Queenfisher compatible types의 Wrapper입니다. 18 | /// `qf` 메서드를 제공합니다. 19 | public struct QueenfisherWrapper { 20 | 21 | // MARK: - Properties 22 | public let base: Base 23 | 24 | // MARK: - Methods 25 | public init(base: Base) { 26 | self.base = base 27 | } 28 | } 29 | 30 | /// Object 타입을 위한 Queenfisher namespace입니다. 31 | public protocol QueenfisherCompatible: AnyObject {} 32 | 33 | extension QueenfisherCompatible { 34 | 35 | /// `QueenfisherCompatible` namespace입니다. 36 | public var qf: QueenfisherWrapper { 37 | return QueenfisherWrapper(base: self) 38 | } 39 | } 40 | 41 | // MARK: - Conforms Queenfisher Compatible 42 | extension QFImage: QueenfisherCompatible {} 43 | extension QFImageView: QueenfisherCompatible {} 44 | extension QFButton: QueenfisherCompatible {} 45 | -------------------------------------------------------------------------------- /Trinap/Sources/Data/DTO/ChatDTO.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatDTO.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/16. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ChatDTO: Codable { 12 | 13 | // MARK: - Properties 14 | let chatId: String 15 | let senderUserId: String 16 | let chatType: Chat.ChatType 17 | let content: String 18 | let isChecked: Bool 19 | let createdAt: String 20 | let imageWidth: Double? 21 | let imageHeight: Double? 22 | 23 | // MARK: - Methods 24 | func toModel(clientId: String) -> Chat { 25 | return Chat( 26 | chatId: chatId, 27 | senderUserId: senderUserId, 28 | senderType: getSenderType(clientId: clientId), 29 | chatType: chatType, 30 | content: content, 31 | isChecked: isChecked, 32 | createdAt: Date.fromStringOrNow(createdAt), 33 | imageWidth: imageWidth, 34 | imageHeight: imageHeight 35 | ) 36 | } 37 | 38 | private func getSenderType(clientId: String) -> Chat.SenderType { 39 | if clientId == self.senderUserId { 40 | return .mine 41 | } else { 42 | return .other 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/MyPage/MyPage/Tableview/MyPageSwitchRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyPageSwitchRow.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/09. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | import UIKit 9 | 10 | final class MyPageSwitchRow: BaseTableViewCell { 11 | 12 | private lazy var infoLabel = UILabel().than { 13 | $0.text = "작가 프로필 노출" 14 | } 15 | 16 | lazy var exposureSwitch = UISwitch() 17 | 18 | override func configureHierarchy() { 19 | self.contentView.addSubviews([infoLabel, exposureSwitch]) 20 | } 21 | 22 | override func configureConstraints() { 23 | infoLabel.snp.makeConstraints { make in 24 | make.leading.equalToSuperview().offset(trinapOffset * 2) 25 | make.centerY.equalToSuperview() 26 | } 27 | 28 | self.exposureSwitch.snp.makeConstraints { make in 29 | make.centerY.equalToSuperview() 30 | make.trailing.equalToSuperview().inset(trinapOffset * 2) 31 | } 32 | } 33 | 34 | override func configureAttributes() { 35 | self.selectionStyle = .none 36 | } 37 | 38 | func configure(isExposure: Bool) { 39 | self.exposureSwitch.isOn = isExposure 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Queenfisher/Sources/ImageCache/ImageCacheConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCacheConfig.swift 3 | // Queenfisher 4 | // 5 | // Created by kimchansoo on 2022/12/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct MemoryConfig { 12 | var totalCostLimit: Int = 150 * 1024 * 1024 // 메모리 캐시 최대 용량. 13 | var countLimit: Int = 50 // 메모리 캐시 최대 적재 개수. 14 | } 15 | 16 | typealias DiskConfig = Int 17 | 18 | public enum ConfigType { 19 | case lower 20 | case normal 21 | case high 22 | 23 | var memoryConfig: MemoryConfig { 24 | switch self { 25 | case .lower: 26 | return MemoryConfig( 27 | totalCostLimit: 70 * 1024 * 1024, 28 | countLimit: 25 29 | ) 30 | case .normal: 31 | return MemoryConfig() 32 | case .high: 33 | return MemoryConfig( 34 | totalCostLimit: 300 * 1024 * 1024, 35 | countLimit: 75 36 | ) 37 | } 38 | } 39 | 40 | var diskConfig: DiskConfig { 41 | switch self { 42 | case .lower: 43 | return 30 44 | case .normal: 45 | return 50 46 | case .high: 47 | return 70 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LocationCache/Sources/Cache/MemoryLocationCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryLocationCache.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/12/27. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreLocation 11 | 12 | struct MemoryLocationCache: LocationCacheProtocol { 13 | 14 | // MARK: - Properties 15 | private let cache = NSCache() 16 | private let diskLocationCache = DiskLocationCache() 17 | 18 | // MARK: - Methods 19 | func reverseGeocodeLocation(_ location: CLLocation, preferredLocale: Locale?, completionHandler: @escaping (String, Error?) -> Void) { 20 | let key = key(for: location) as NSString 21 | 22 | if let address = cache.object(forKey: key) { 23 | completionHandler(address as String, nil) 24 | return 25 | } 26 | 27 | diskLocationCache.reverseGeocodeLocation(location, preferredLocale: preferredLocale) { address, error in 28 | if let error { 29 | completionHandler(address, error) 30 | return 31 | } 32 | 33 | cache.setObject(address as NSString, forKey: key) 34 | 35 | completionHandler(address, error) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Extension/UINavigationController+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+.swift 3 | // Trinap 4 | // 5 | // Created by Doyun Park on 2022/12/05. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UINavigationController { 12 | 13 | func pushViewControllerHideBottomBar(rootViewController: UIViewController, isNavigationBarHidden: Bool = false, animated: Bool) { 14 | self.navigationBar.isHidden = isNavigationBarHidden 15 | self.navigationBar.topItem?.title = "" 16 | self.viewControllers.first?.hidesBottomBarWhenPushed = true 17 | self.pushViewController(rootViewController, animated: animated) 18 | self.viewControllers.first?.hidesBottomBarWhenPushed = false 19 | } 20 | 21 | func setLeftArrowBackButton() { 22 | let backButtonImage = UIImage(systemName: "arrow.left")? 23 | .withTintColor(TrinapAsset.black.color, renderingMode: .alwaysOriginal) 24 | 25 | self.navigationBar.backIndicatorImage = backButtonImage 26 | self.navigationBar.backIndicatorTransitionMaskImage = backButtonImage 27 | self.navigationBar.topItem?.backButtonTitle = "" 28 | } 29 | 30 | func setShadowImage() { 31 | self.navigationBar.shadowImage = nil 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Than/Sources/Than.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Than.swift 3 | // Trinap 4 | // 5 | // Created by 김세영 on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol Than {} 12 | 13 | extension Than where Self: Any { 14 | 15 | /// Value Type의 인스턴스를 생성한 후 `apply`을 통해 여러 설정을 진행합니다. 16 | /// - Parameter apply: 설정을 진행할 클로저입니다. 17 | /// - Returns: `apply`의 설정이 반영된 인스턴스를 반환합니다. 18 | public func configure(_ apply: (inout Self) throws -> Void) rethrows -> Self { 19 | var mutableSelf = self 20 | 21 | try apply(&mutableSelf) 22 | return mutableSelf 23 | } 24 | } 25 | 26 | extension Than where Self: AnyObject { 27 | 28 | /// 인스턴스를 생성한 후 `apply`를 통해 설정을 진행합니다. 29 | /// - Parameter apply: 설정을 진행할 클로저입니다. 30 | /// - Returns: `apply`의 설정이 반영된 인스턴스를 반환합니다. 31 | public func than(_ apply: (Self) throws -> Void) rethrows -> Self { 32 | try apply(self) 33 | return self 34 | } 35 | } 36 | 37 | extension NSObject: Than {} 38 | 39 | extension CGPoint: Than {} 40 | extension CGRect: Than {} 41 | extension CGSize: Than {} 42 | 43 | extension Array: Than {} 44 | extension Dictionary: Than {} 45 | extension Set: Than {} 46 | 47 | extension UIEdgeInsets: Than {} 48 | extension UIOffset: Than {} 49 | extension UIRectEdge: Than {} 50 | -------------------------------------------------------------------------------- /Trinap/Sources/Domain/UseCases/Chat/DefaultCreateChatroomUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCreateChatroomUseCase.swift 3 | // Trinap 4 | // 5 | // Created by kimchansoo on 2022/12/05. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import RxSwift 12 | 13 | final class DefaultCreateChatroomUseCase: CreateChatroomUseCase { 14 | 15 | // MARK: Properties 16 | private let chatroomRepository: ChatroomRepository 17 | 18 | // MARK: Initializers 19 | init(chatroomRepository: ChatroomRepository) { 20 | self.chatroomRepository = chatroomRepository 21 | } 22 | 23 | // MARK: Methods 24 | func create(photographerUserId: String) -> Observable { 25 | chatroomRepository.fetchChatrooms() 26 | .map { 27 | $0.filter { $0.photographerUserId == photographerUserId || $0.customerUserId == photographerUserId } 28 | } 29 | .withUnretained(self) 30 | .flatMap { owner, chatrooms -> Observable in 31 | guard let chatroom = chatrooms.first 32 | else { 33 | return owner.chatroomRepository.create(photographerUserId: photographerUserId) 34 | } 35 | return Observable.just(chatroom.chatroomId) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TrinapTests/Sources/TrinapTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrinapTests.swift 3 | // TrinapTests 4 | // 5 | // Created by 김세영 on 2022/11/17. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | final class TrinapTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | // Any test you write for XCTest can be annotated as throws and async. 25 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 26 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Trinap/Sources/App/Splash/SplashViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SplashViewModel.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/22. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import FirebaseAuth 12 | import RxCocoa 13 | import RxRelay 14 | import RxSwift 15 | 16 | final class SplashViewModel: ViewModelType { 17 | 18 | struct Input { } 19 | 20 | struct Output { } 21 | 22 | // MARK: - Properties 23 | let disposeBag = DisposeBag() 24 | weak var coordinator: AppCoordinator? 25 | private let signInUseCase: SignInUseCase 26 | private let auth = DefaultAuthRepository() 27 | 28 | // MARK: - Initializer 29 | init( 30 | signInUseCase: SignInUseCase, 31 | coordinator: AppCoordinator 32 | ) { 33 | self.signInUseCase = signInUseCase 34 | self.coordinator = coordinator 35 | } 36 | 37 | // MARK: - Methods 38 | func transform(input: Input) -> Output { 39 | return Output() 40 | } 41 | 42 | func autoSignInFlow() { 43 | self.signInUseCase.autoSignIn() 44 | .withUnretained(self) 45 | .subscribe(onNext: { owner, isSignIn in 46 | isSignIn ? owner.coordinator?.connectTabBarFlow() : owner.coordinator?.connectAuthFlow() 47 | }) 48 | .disposed(by: disposeBag) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/Common/Reusable/PlaceHolderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceHolderView.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/12/13. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import SnapKit 12 | import Than 13 | 14 | final class PlaceHolderView: BaseView { 15 | 16 | // MARK: - UI 17 | private lazy var descriptionLabel = UILabel().than { 18 | $0.textColor = TrinapAsset.black.color 19 | $0.font = TrinapFontFamily.Pretendard.regular.font(size: 16) 20 | } 21 | 22 | // MARK: - Properties 23 | 24 | // MARK: - Initializers 25 | init(text: String) { 26 | super.init(frame: .zero) 27 | 28 | self.descriptionLabel.text = text 29 | } 30 | 31 | // MARK: - Methods 32 | override func configureHierarchy() { 33 | super.configureHierarchy() 34 | 35 | self.addSubview(descriptionLabel) 36 | } 37 | 38 | override func configureConstraints() { 39 | super.configureConstraints() 40 | 41 | self.descriptionLabel.snp.makeConstraints { make in 42 | make.top.equalToSuperview().offset(trinapOffset * 10) 43 | make.centerX.equalToSuperview() 44 | } 45 | } 46 | 47 | func updateDescriptionText(_ text: String) { 48 | self.descriptionLabel.text = text 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Trinap/Sources/Presenter/TabBar/Coordinator/TabBarPageType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabBarPageType.swift 3 | // Trinap 4 | // 5 | // Created by ByeongJu Yu on 2022/11/19. 6 | // Copyright © 2022 Trinap. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | enum TabBarPageType: Int, CaseIterable { 13 | case main = 0, chat, reservation, myPage 14 | 15 | // MARK: - Properties 16 | var tabBarItem: UITabBarItem { 17 | switch self { 18 | case .main: 19 | return UITabBarItem( 20 | title: "홈", 21 | image: TrinapAsset.home.image, 22 | selectedImage: TrinapAsset.selectHome.image 23 | ) 24 | case .chat: 25 | return UITabBarItem( 26 | title: "채팅", 27 | image: TrinapAsset.chat.image, 28 | selectedImage: TrinapAsset.selectedChat.image 29 | ) 30 | case .reservation: 31 | return UITabBarItem( 32 | title: "예약 내역", 33 | image: TrinapAsset.reservation.image, 34 | selectedImage: TrinapAsset.selectedReservation.image 35 | ) 36 | case .myPage: 37 | return UITabBarItem( 38 | title: "마이페이지", 39 | image: TrinapAsset.user.image, 40 | selectedImage: TrinapAsset.selectUser.image 41 | ) 42 | } 43 | } 44 | } 45 | --------------------------------------------------------------------------------