├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── 🐞-bug-template.md
│ └── 💡-issue-template.md
├── pull_request_template.md
├── secrets
│ ├── Secrets.xcconfig.gpg
│ ├── layoverProfile
│ └── mobileprovision
└── workflows
│ └── ios-pr-test.yml
├── .gitignore
├── .idea
├── .gitignore
├── iOS09-Layover.iml
├── inspectionProfiles
│ └── Project_Default.xml
├── jsLinters
│ └── eslint.xml
├── modules.xml
├── prettier.xml
└── vcs.xml
├── BE
├── .gitkeep
└── layover
│ ├── .eslintrc.js
│ ├── .prettierrc
│ ├── Dockerfile
│ ├── Jenkinsfile_CD
│ ├── Jenkinsfile_CI
│ ├── README.md
│ ├── docker-compose.yml
│ ├── dockerignore
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prometheus.yml
│ ├── public
│ ├── apps
│ │ ├── 0.2.0
│ │ │ ├── Layover.ipa
│ │ │ └── manifest.plist
│ │ ├── 0.3.0
│ │ │ ├── Layover.ipa
│ │ │ └── manifest.plist
│ │ ├── 0.4.0
│ │ │ ├── Layover.ipa
│ │ │ └── manifest.plist
│ │ ├── Layover.ipa
│ │ ├── images
│ │ │ ├── layover_1.png
│ │ │ └── layover_2.png
│ │ └── manifest.plist
│ ├── iOS.html
│ └── images
│ │ └── kong.jpeg
│ ├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── board
│ │ ├── board.controller.spec.ts
│ │ ├── board.controller.ts
│ │ ├── board.entity.ts
│ │ ├── board.fixture.ts
│ │ ├── board.module.ts
│ │ ├── board.provider.ts
│ │ ├── board.repository.ts
│ │ ├── board.service.ts
│ │ ├── board.swagger.ts
│ │ └── dtos
│ │ │ ├── board-pre-signed-url.dto.ts
│ │ │ ├── board-res-dto.ts
│ │ │ ├── boards-res.dto.ts
│ │ │ ├── create-board-res.dto.ts
│ │ │ ├── create-board.dto.ts
│ │ │ ├── encoding-callback.dto.ts
│ │ │ └── upload-callback.dto.ts
│ ├── config.ts
│ ├── database
│ │ ├── database.module.ts
│ │ └── database.provider.ts
│ ├── main.ts
│ ├── member
│ │ ├── dtos
│ │ │ ├── check-username-res.dto.ts
│ │ │ ├── check-username.dto.ts
│ │ │ ├── delete-member-res.dto.ts
│ │ │ ├── introduce-res.dto.ts
│ │ │ ├── introduce.dto.ts
│ │ │ ├── member-infos-res.dto.ts
│ │ │ ├── profile-pre-signed-url.dto.ts
│ │ │ ├── username-res.dto.ts
│ │ │ └── username.dto.ts
│ │ ├── member.controller.ts
│ │ ├── member.entity.ts
│ │ ├── member.module.ts
│ │ ├── member.providers.ts
│ │ ├── member.repository.ts
│ │ ├── member.service.ts
│ │ └── member.swagger.ts
│ ├── oauth
│ │ ├── dtos
│ │ │ ├── apple-login.dto.ts
│ │ │ ├── apple-signup.dto.ts
│ │ │ ├── check-signup-res-dto.ts
│ │ │ ├── kakao-login.dto.ts
│ │ │ ├── kakao-signup.dto.ts
│ │ │ └── token-res.dto.ts
│ │ ├── oauth.controller.spec.ts
│ │ ├── oauth.controller.ts
│ │ ├── oauth.module.ts
│ │ ├── oauth.repository.ts
│ │ ├── oauth.service.spec.ts
│ │ ├── oauth.service.ts
│ │ └── oauth.swagger.ts
│ ├── pipes
│ │ ├── custom-header.decorator.ts
│ │ └── jwt.validation.pipe.ts
│ ├── redis
│ │ ├── redis.module.ts
│ │ └── redis.provider.ts
│ ├── report
│ │ ├── dtos
│ │ │ ├── report-res.dto.ts
│ │ │ └── report.dto.ts
│ │ ├── report.controller.ts
│ │ ├── report.entity.ts
│ │ ├── report.module.ts
│ │ ├── report.provider.ts
│ │ ├── report.service.ts
│ │ └── report.swagger.ts
│ ├── response
│ │ ├── custom-response.ts
│ │ └── ecustom-code.jenum.ts
│ ├── tag
│ │ ├── tag.entity.ts
│ │ ├── tag.module.ts
│ │ ├── tag.provider.ts
│ │ ├── tag.repository.ts
│ │ └── tag.service.ts
│ └── utils
│ │ ├── hashUtils.ts
│ │ ├── interfaces
│ │ └── token.payload.d.ts
│ │ ├── jwtUtils.ts
│ │ ├── logging-interceptor.ts
│ │ ├── my-logger.ts
│ │ ├── pre-signed-url-res.dto.ts
│ │ ├── s3Utils.ts
│ │ └── swaggerUtils.ts
│ ├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── README.md
└── iOS
└── Layover
├── .swiftlint.yml
├── Layover.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
└── xcshareddata
│ └── xcschemes
│ └── Layover.xcscheme
├── Layover
├── AppDelegate.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
├── DesignSystem
│ ├── LOButton.swift
│ ├── LOCircleButton.swift
│ ├── LODescriptionView.swift
│ ├── LOImageLabel.swift
│ ├── LOPopUpView.swift
│ ├── LOReportContentView.swift
│ ├── LOReportStackView.swift
│ ├── LOSlider.swift
│ ├── LOTagStackView.swift
│ ├── LOTextField.swift
│ ├── LOTextLabel.swift
│ └── LOTextView.swift
├── Extensions
│ ├── AVFileType+.swift
│ ├── Notification.Name+.swift
│ ├── OSLog+.swift
│ ├── Sequence+.swift
│ ├── UICollectionViewLayout+.swift
│ ├── UIFont+.swift
│ ├── UIView+.swift
│ ├── UIViewController+.swift
│ ├── URL+.swift
│ └── URLSession+.swift
├── Info.plist
├── LOImageCacher
│ ├── .gitignore
│ ├── .swiftpm
│ │ └── xcode
│ │ │ └── package.xcworkspace
│ │ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Package.swift
│ ├── Sources
│ │ └── LOImageCacher
│ │ │ ├── ImageView + LOImageCacherWrapper.swift
│ │ │ ├── LOCacheStorage.swift
│ │ │ ├── LOImageCacher.swift
│ │ │ └── LOImageFetcher.swift
│ └── Tests
│ │ └── LOImageCacherTests
│ │ └── LOImageCacherTests.swift
├── Layover.entitlements
├── Models
│ ├── Board.swift
│ ├── Member.swift
│ ├── Post.swift
│ ├── PostsPage.swift
│ └── UploadPost.swift
├── Network
│ ├── AuthManager.swift
│ ├── Common
│ │ └── NetworkError.swift
│ ├── DTOs
│ │ ├── BoardDTO.swift
│ │ ├── CheckSignUpDTO.swift
│ │ ├── CheckUserNameDTO.swift
│ │ ├── IntroduceDTO.swift
│ │ ├── LoginDTO.swift
│ │ ├── MemberDTO.swift
│ │ ├── NicknameDTO.swift
│ │ ├── PostDTO.swift
│ │ ├── PostsPageDTO.swift
│ │ ├── PresignedURLDTO.swift
│ │ ├── ProfileImageDTO.swift
│ │ ├── ReportDTO.swift
│ │ ├── Response.swift
│ │ ├── UploadPostDTO.swift
│ │ └── UploadVideoDTO.swift
│ ├── EndPoint
│ │ ├── EndPoint.swift
│ │ ├── Factories
│ │ │ ├── DefaultPostManagerEndPointFactory.swift
│ │ │ ├── LoginEndPointFactory.swift
│ │ │ ├── PostEndPointFactory.swift
│ │ │ ├── SignUpEndPointFactory.swift
│ │ │ ├── UploadPostEndPointFactory.swift
│ │ │ └── UserEndPointFactory.swift
│ │ ├── HTTPMethod.swift
│ │ ├── Requestable.swift
│ │ └── Responsable.swift
│ ├── Mock
│ │ ├── MockData
│ │ │ ├── CheckSignUp.json
│ │ │ ├── CheckUserName.json
│ │ │ ├── DeleteUser.json
│ │ │ ├── DeleteVideo.json
│ │ │ ├── GetMember.json
│ │ │ ├── LoginData.json
│ │ │ ├── PatchIntroduce.json
│ │ │ ├── PatchProfileImage.json
│ │ │ ├── PatchUserName.json
│ │ │ ├── PostList.json
│ │ │ ├── PostListEnd.json
│ │ │ ├── PostListMore.json
│ │ │ └── ReportPlaybackVideo.json
│ │ └── MockURLProtocol.swift
│ ├── Prefetcher
│ │ └── Prefetcher.swift
│ └── Provider
│ │ └── Provider.swift
├── Resources
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ └── LayoverIcon.png
│ │ ├── Colors
│ │ │ ├── Background.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Correct.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── DarkGrey.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Error.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Grey100.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Grey200.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Grey300.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Grey400.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Grey500.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── Kakao.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── LayoverWhite.colorset
│ │ │ │ └── Contents.json
│ │ │ └── PrimaryPurple.colorset
│ │ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── LONormalThumb.imageset
│ │ │ ├── Contents.json
│ │ │ ├── normalImage 1.png
│ │ │ ├── normalImage 2.png
│ │ │ └── normalImage.png
│ │ ├── LOSelectedThumb.imageset
│ │ │ ├── Contents.json
│ │ │ ├── selectedImage 1.png
│ │ │ ├── selectedImage 2.png
│ │ │ └── selectedImage.png
│ │ ├── LocationPin.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LocationPin.png
│ │ │ ├── LocationPin@2x.png
│ │ │ └── LocationPin@3x.png
│ │ ├── Setting.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Setting.png
│ │ │ ├── Setting@2x.png
│ │ │ └── Setting@3x.png
│ │ ├── Title.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Title.png
│ │ │ ├── Title@2x.png
│ │ │ └── Title@3x.png
│ │ ├── appleLogo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── appleLogo 1.png
│ │ │ ├── appleLogo 2.png
│ │ │ └── appleLogo.png
│ │ ├── close.imageset
│ │ │ ├── Close Button.png
│ │ │ ├── Close Button@2x.png
│ │ │ ├── Close Button@3x.png
│ │ │ └── Contents.json
│ │ ├── content.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Document.png
│ │ │ ├── Document@2x.png
│ │ │ └── Document@3x.png
│ │ ├── down.imageset
│ │ │ ├── Contents.json
│ │ │ ├── leading-icon.png
│ │ │ ├── leading-icon@2x.png
│ │ │ └── leading-icon@3x.png
│ │ ├── icon_tab_back.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_tab_back.png
│ │ │ ├── icon_tab_back@2x.png
│ │ │ └── icon_tab_back@3x.png
│ │ ├── kakaoLogo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── kakaoLogo 1.png
│ │ │ ├── kakaoLogo 2.png
│ │ │ └── kakaoLogo.png
│ │ ├── loLogo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LayoverLogo 1.png
│ │ │ ├── LayoverLogo 2.png
│ │ │ └── LayoverLogo.png
│ │ ├── map.imageset
│ │ │ ├── Contents.json
│ │ │ ├── map.png
│ │ │ ├── map@2x.png
│ │ │ └── map@3x.png
│ │ ├── mapPin.imageset
│ │ │ ├── Contents.json
│ │ │ ├── map_pin_highlighted.png
│ │ │ ├── map_pin_highlighted@2x.png
│ │ │ └── map_pin_highlighted@3x.png
│ │ ├── mute.imageset
│ │ │ ├── Contents.json
│ │ │ ├── mute_icon.png
│ │ │ ├── mute_icon@2x.png
│ │ │ └── mute_icon@3x.png
│ │ ├── myLocation.imageset
│ │ │ ├── Contents.json
│ │ │ ├── location_icon.png
│ │ │ ├── location_icon@2x.png
│ │ │ └── location_icon@3x.png
│ │ ├── pause.imageset
│ │ │ ├── Contents.json
│ │ │ ├── pause 1.png
│ │ │ ├── pause 2.png
│ │ │ └── pause.png
│ │ ├── photo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── photo_icon.png
│ │ │ ├── photo_icon@2x.png
│ │ │ └── photo_icon@3x.png
│ │ ├── planet.imageset
│ │ │ ├── Contents.json
│ │ │ ├── planet.png
│ │ │ ├── planet@2x.png
│ │ │ └── planet@3x.png
│ │ ├── play.imageset
│ │ │ ├── Contents.json
│ │ │ ├── play 1.png
│ │ │ ├── play 2.png
│ │ │ └── play.png
│ │ ├── plus.imageset
│ │ │ ├── Contents.json
│ │ │ ├── plus_icon.png
│ │ │ ├── plus_icon@2x.png
│ │ │ └── plus_icon@3x.png
│ │ ├── profile.imageset
│ │ │ ├── Contents.json
│ │ │ ├── profile.png
│ │ │ ├── profile@2x.png
│ │ │ └── profile@3x.png
│ │ ├── retry.imageset
│ │ │ ├── Contents.json
│ │ │ ├── interface-arrows-round-right--diagram-round-arrow-right.png
│ │ │ ├── interface-arrows-round-right--diagram-round-arrow-right@2x.png
│ │ │ └── interface-arrows-round-right--diagram-round-arrow-right@3x.png
│ │ ├── scissors.imageset
│ │ │ ├── Contents.json
│ │ │ ├── scissors_icon.png
│ │ │ ├── scissors_icon@2x.png
│ │ │ └── scissors_icon@3x.png
│ │ ├── smallPlus.imageset
│ │ │ ├── Contents.json
│ │ │ ├── smallPlus.png
│ │ │ ├── smallPlus@2x.png
│ │ │ └── smallPlus@3x.png
│ │ ├── star.imageset
│ │ │ ├── 3.png
│ │ │ ├── 3@2x.png
│ │ │ ├── 3@3x.png
│ │ │ └── Contents.json
│ │ ├── tag.imageset
│ │ │ ├── Contents.json
│ │ │ ├── box.png
│ │ │ ├── box@2x.png
│ │ │ └── box@3x.png
│ │ └── volume.imageset
│ │ │ ├── Contents.json
│ │ │ ├── volume_icon.png
│ │ │ ├── volume_icon@2x.png
│ │ │ └── volume_icon@3x.png
│ └── Fonts
│ │ ├── Dashboard-Regular.ttf
│ │ ├── Pretendard-Bold.ttf
│ │ ├── Pretendard-Regular.ttf
│ │ └── Pretendard-SemiBold.ttf
├── SceneDelegate.swift
├── Scenes
│ ├── BaseViewController.swift
│ ├── Configurator.swift
│ ├── EditProfile
│ │ ├── EditProfileConfigurator.swift
│ │ ├── EditProfileInteractor.swift
│ │ ├── EditProfileModels.swift
│ │ ├── EditProfilePresenter.swift
│ │ ├── EditProfileRouter.swift
│ │ └── EditProfileViewController.swift
│ ├── EditTag
│ │ ├── EditTagConfigurator.swift
│ │ ├── EditTagInteractor.swift
│ │ ├── EditTagModels.swift
│ │ ├── EditTagPresenter.swift
│ │ ├── EditTagRouter.swift
│ │ └── EditTagViewController.swift
│ ├── EditVideo
│ │ ├── EditVideoConfigurator.swift
│ │ ├── EditVideoInteractor.swift
│ │ ├── EditVideoModels.swift
│ │ ├── EditVideoPresenter.swift
│ │ ├── EditVideoRouter.swift
│ │ ├── EditVideoViewController.swift
│ │ └── EditVideoWorker.swift
│ ├── Home
│ │ ├── Cell
│ │ │ └── HomeCarouselCollectionViewCell.swift
│ │ ├── HomeConfigurator.swift
│ │ ├── HomeInteractor.swift
│ │ ├── HomeModels.swift
│ │ ├── HomePresenter.swift
│ │ ├── HomeRouter.swift
│ │ ├── HomeViewController.swift
│ │ └── HomeWorker.swift
│ ├── Login
│ │ ├── LoginConfigurator.swift
│ │ ├── LoginInteractor.swift
│ │ ├── LoginModels.swift
│ │ ├── LoginPresenter.swift
│ │ ├── LoginRouter.swift
│ │ ├── LoginViewController.swift
│ │ └── LoginWorker.swift
│ ├── Map
│ │ ├── LOAnnotation.swift
│ │ ├── MapConfigurator.swift
│ │ ├── MapInteractor.swift
│ │ ├── MapModels.swift
│ │ ├── MapPresenter.swift
│ │ ├── MapRouter.swift
│ │ ├── MapViewController.swift
│ │ ├── MapWorker.swift
│ │ └── Views
│ │ │ ├── LOAnnotationView.swift
│ │ │ └── MapCarouselCollectionViewCell.swift
│ ├── Playback
│ │ ├── Cell
│ │ │ └── PlaybackCell.swift
│ │ ├── PlaybackConfigurator.swift
│ │ ├── PlaybackInteractor.swift
│ │ ├── PlaybackModels.swift
│ │ ├── PlaybackPresenter.swift
│ │ ├── PlaybackRouter.swift
│ │ ├── PlaybackView.swift
│ │ ├── PlaybackViewController.swift
│ │ └── PlaybackWorker.swift
│ ├── Profile
│ │ ├── ProfileConfigurator.swift
│ │ ├── ProfileInteractor.swift
│ │ ├── ProfileModels.swift
│ │ ├── ProfilePresenter.swift
│ │ ├── ProfileRouter.swift
│ │ ├── ProfileViewController.swift
│ │ └── Views
│ │ │ ├── ProfileCollectionViewCell.swift
│ │ │ └── ThumbnailCollectionViewCell.swift
│ ├── Report
│ │ ├── ReportConfigurator.swift
│ │ ├── ReportInteractor.swift
│ │ ├── ReportModels.swift
│ │ ├── ReportPresenter.swift
│ │ ├── ReportRouter.swift
│ │ ├── ReportViewController.swift
│ │ └── ReportWorker.swift
│ ├── Setting
│ │ ├── SettingConfigurator.swift
│ │ ├── SettingInteractor.swift
│ │ ├── SettingModels.swift
│ │ ├── SettingPresenter.swift
│ │ ├── SettingRouter.swift
│ │ ├── SettingViewController.swift
│ │ └── SettingWorker.swift
│ ├── SignUpScene
│ │ ├── SignUpConfigurator.swift
│ │ ├── SignUpInteractor.swift
│ │ ├── SignUpModels.swift
│ │ ├── SignUpPresenter.swift
│ │ ├── SignUpRouter.swift
│ │ └── SignUpWorker.swift
│ ├── SignUpViewController.swift
│ ├── Tabbar
│ │ ├── MainTabBarConfigurator.swift
│ │ └── MainTabBarViewController.swift
│ ├── TagPlayList
│ │ ├── Cell
│ │ │ └── TagPlayListCollectionViewCell.swift
│ │ ├── TagPlayListConfigurator.swift
│ │ ├── TagPlayListInteractor.swift
│ │ ├── TagPlayListModels.swift
│ │ ├── TagPlayListPresenter.swift
│ │ ├── TagPlayListRouter.swift
│ │ ├── TagPlayListViewController.swift
│ │ └── TagPlayListWorker.swift
│ ├── UIComponents
│ │ ├── LoopingPlayerView.swift
│ │ ├── PlayerView.swift
│ │ └── Toast.swift
│ └── UploadPost
│ │ ├── UploadPostConfigurator.swift
│ │ ├── UploadPostInteractor.swift
│ │ ├── UploadPostModels.swift
│ │ ├── UploadPostPresenter.swift
│ │ ├── UploadPostRouter.swift
│ │ ├── UploadPostViewController.swift
│ │ ├── UploadPostWorker.swift
│ │ └── VideoPickerManager.swift
├── Services
│ ├── HLSResourceLoader
│ │ ├── HLSAssetResourceLoaderDelegate.swift
│ │ └── HLSSliceResourceLoader.swift
│ ├── Keychain
│ │ └── KeychainStored.swift
│ ├── Location
│ │ ├── CurrentLocationManager.swift
│ │ └── LocationFetcher.swift
│ ├── System.swift
│ └── UserDefaults
│ │ └── UserDefaultStored.swift
├── Workers
│ ├── Mocks
│ │ ├── MockHomeWorker.swift
│ │ ├── MockLoginWorker.swift
│ │ ├── MockPlaybackWorker.swift
│ │ ├── MockReportWorker.swift
│ │ ├── MockSignUpWorker.swift
│ │ ├── MockTagPlayListWorker.swift
│ │ ├── MockUserWorker.swift
│ │ ├── StubAuthManager.swift
│ │ └── sample.jpeg
│ ├── UserWorker.swift
│ └── VideoFileWorker.swift
└── en.lproj
│ └── LaunchScreen.strings
└── LayoverTests
├── Mocks
├── LocationFetcher
│ └── MockLocationFetcher.swift
├── MockDatas
│ ├── CheckSignUp.json
│ ├── CheckUserName.json
│ ├── DeleteUser.json
│ ├── DeleteVideo.json
│ ├── GetMember.json
│ ├── LoginData.json
│ ├── PatchIntroduce.json
│ ├── PatchProfileImage.json
│ ├── PatchUserName.json
│ ├── PostBoard.json
│ ├── PostList.json
│ ├── PostListEnd.json
│ ├── PostListMore.json
│ ├── PostsPage.json
│ ├── ReportPlaybackVideo.json
│ └── sample.jpeg
└── Workers
│ ├── MockHomeWorker.swift
│ ├── MockPlaybackWorker.swift
│ ├── MockSettingWorker.swift
│ ├── MockSignUpWorker.swift
│ ├── MockTagPlayListWorker.swift
│ ├── MockUploadPostWorker.swift
│ └── MockUserWorker.swift
├── Scenes
├── EditProfile
│ ├── EditProfileInteractorTests.swift
│ └── EditProfilePresenterTests.swift
├── Home
│ ├── HomeInteractorTests.swift
│ ├── HomePresenterTests.swift
│ ├── HomeViewControllerTests.swift
│ └── HomeWorkerTests.swift
├── Playback
│ ├── PlaybackInteractorTests.swift
│ └── PlaybackPresenterTests.swift
├── Profile
│ ├── ProfileInteractorTests.swift
│ ├── ProfilePresenterTests.swift
│ └── ProfileViewControllerTests.swift
├── Setting
│ ├── SettingInteractorTests.swift
│ ├── SettingPresenterTests.swift
│ └── SettingViewControllerTests.swift
├── SignUp
│ ├── SignUpInteractorTests.swift
│ ├── SignUpPresenterTests.swift
│ └── SignUpWorkerTests.swift
├── TagPlayList
│ ├── TagPlayListInteractorTests.swift
│ ├── TagPlayListPresenterTests.swift
│ ├── TagPlayListViewControllerTests.swift
│ └── TagPlayListWorkerTests.swift
└── UploadPost
│ ├── UploadPostInteractorTests.swift
│ ├── UploadPostPresenterTests.swift
│ ├── UploadPostViewControllerTests.swift
│ └── UploadPostWorkerTests.swift
├── Seeds.swift
└── Stubs
└── StubAuthManager.swift
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj binary merge=union
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/🐞-bug-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41E Bug Template"
3 | about: Create a report to help us improve
4 | title: 'bug: ...'
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 🐞 버그 설명
11 | 스크린 샷, 작동 환경 (OS, device 등)을 적어주세요.
12 |
13 | ## 📝 todo
14 | - [ ] todo !
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/💡-issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F4A1 Issue Template"
3 | about: Suggest an idea for this project
4 | title: 'feat: ...'
5 | labels: feature
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 💡 issue
11 | 이슈에 대한 내용을 설명해주세요.
12 |
13 | ## 📝 todo
14 | - [ ] todo !
15 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## 🧑🚀 PR 요약
2 | 해당 pr에서 작업한 내역을 적어주세요.
3 |
4 | #### 📌 변경 사항
5 | 변경사항 및 주의 사항 (모듈 설치 등)을 적어주세요.
6 |
7 | ##### 📸 ScreenShot
8 | 작동, 구현화면
9 |
10 | ##### ✅ PR check list
11 | ```
12 | - commit message가 적절한지 확인해주세요.
13 | - 마지막으로 Coding Convention을 준수했는지 확인해주세요.
14 | - 적절한 branch로 요청했는지 확인해주세요.
15 | - Assignees, Label을 붙여주세요.
16 | - 가능한 이슈를 Link 해주세요.
17 | - PR이 승인된 경우 해당 브랜치는 삭제해주세요.
18 | ```
19 |
20 | #### Linked Issue
21 | close #
22 |
--------------------------------------------------------------------------------
/.github/secrets/Secrets.xcconfig.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/.github/secrets/Secrets.xcconfig.gpg
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/iOS09-Layover.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jsLinters/eslint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/prettier.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/BE/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/.gitkeep
--------------------------------------------------------------------------------
/BE/layover/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | project: 'tsconfig.json',
5 | tsconfigRootDir: __dirname,
6 | sourceType: 'module',
7 | },
8 | plugins: ['@typescript-eslint/eslint-plugin'],
9 | extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
10 | root: true,
11 | env: {
12 | node: true,
13 | jest: true,
14 | },
15 | ignorePatterns: ['.eslintrc.js'],
16 | rules: {
17 | 'prettier/prettier': ['error', { endOfLine: 'auto', printWidth: 120 }],
18 | '@typescript-eslint/interface-name-prefix': 'off',
19 | '@typescript-eslint/explicit-function-return-type': 'off',
20 | '@typescript-eslint/explicit-module-boundary-types': 'off',
21 | '@typescript-eslint/no-explicit-any': 'off',
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/BE/layover/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "printWidth": 120,
4 | "trailingComma": "all"
5 | }
6 |
--------------------------------------------------------------------------------
/BE/layover/Dockerfile:
--------------------------------------------------------------------------------
1 | # Base Image
2 | FROM node:21
3 |
4 | # Create app directory
5 | WORKDIR /usr/src/app
6 |
7 | COPY package*.json ./
8 |
9 | RUN npm install
10 |
11 | COPY . .
12 |
13 | RUN npm run build
14 |
15 | RUN npm test
16 |
17 | CMD [ "node", "dist/main.js" ]
18 |
19 |
--------------------------------------------------------------------------------
/BE/layover/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | app:
4 | image: ${DOCKER_IMG_NAME}:${COMMIT_HASH}
5 | container_name: layover-container
6 | ports:
7 | - 3000:3000
8 | volumes:
9 | - ~/envs/.env:/usr/src/app/.env
10 | - ~/envs/ca_bundle.crt:/usr/src/app/ca_bundle.crt
11 | - ~/envs/certificate.crt:/usr/src/app/certificate.crt
12 | - ~/envs/private.key:/usr/src/app/private.key
13 | - /var/log/logs.log:/usr/src/app/logs.log
14 | restart: on-failure
15 |
16 | cadvisor:
17 | image: gcr.io/google-containers/cadvisor:latest
18 | container_name: cadvisor
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | restart: always
25 | ports:
26 | - 8090:8080
27 |
28 | prometheus:
29 | image: prom/prometheus
30 | container_name: prometheus
31 | volumes:
32 | - ./prometheus.yml:/etc/prometheus/prometheus.yml
33 | command:
34 | - '--config.file=/etc/prometheus/prometheus.yml'
35 | restart: always
36 | ports:
37 | - 9090:9090
38 |
39 | grafana:
40 | image: grafana/grafana
41 | container_name: grafana
42 | restart: always
43 | ports:
44 | - 3001:3000
--------------------------------------------------------------------------------
/BE/layover/dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | node_modules
4 | npm-debug.log
5 | dist
6 |
--------------------------------------------------------------------------------
/BE/layover/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BE/layover/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 15s
3 | evaluation_interval: 15s
4 |
5 | scrape_configs:
6 | - job_name: 'prometheus'
7 | static_configs:
8 | - targets: ['localhost:9090']
9 |
10 | - job_name: 'cadvisor'
11 | static_configs:
12 | - targets: ['cadvisor:8080']
13 |
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.2.0/Layover.ipa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/0.2.0/Layover.ipa
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.2.0/manifest.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | assets
9 |
10 |
11 | kind
12 | software-package
13 | url
14 | https://layoverapi.shop:3000/apps/0.2.0/Layover.ipa
15 |
16 |
17 | kind
18 | display-image
19 | url
20 | https://layoverapi.shop/apps/images/layover_1.png
21 |
22 |
23 | kind
24 | full-size-image
25 | url
26 | https://layoverapi.shop/apps/images/layover_2.png
27 |
28 |
29 | metadata
30 |
31 | bundle-identifier
32 | kr.codesquad.boostcamp8.Layover
33 | bundle-version
34 | 1.0
35 | kind
36 | software
37 | platform-identifier
38 | com.apple.platform.iphoneos
39 | title
40 | Layover
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.3.0/Layover.ipa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/0.3.0/Layover.ipa
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.3.0/manifest.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | assets
9 |
10 |
11 | kind
12 | software-package
13 | url
14 | https://layoverapi.shop:3000/apps/0.3.0/Layover.ipa
15 |
16 |
17 | kind
18 | display-image
19 | url
20 | https://layoverapi.shop/apps/images/layover_1.png
21 |
22 |
23 | kind
24 | full-size-image
25 | url
26 | https://layoverapi.shop/apps/images/layover_2.png
27 |
28 |
29 | metadata
30 |
31 | bundle-identifier
32 | kr.codesquad.boostcamp8.Layover
33 | bundle-version
34 | 1.0
35 | kind
36 | software
37 | platform-identifier
38 | com.apple.platform.iphoneos
39 | title
40 | Layover
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.4.0/Layover.ipa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/0.4.0/Layover.ipa
--------------------------------------------------------------------------------
/BE/layover/public/apps/0.4.0/manifest.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | assets
9 |
10 |
11 | kind
12 | software-package
13 | url
14 | https://layoverapi.shop:3000/apps/0.4.0/Layover.ipa
15 |
16 |
17 | kind
18 | display-image
19 | url
20 | https://layoverapi.shop/apps/images/layover_1.png
21 |
22 |
23 | kind
24 | full-size-image
25 | url
26 | https://layoverapi.shop/apps/images/layover_2.png
27 |
28 |
29 | metadata
30 |
31 | bundle-identifier
32 | kr.codesquad.boostcamp8.Layover
33 | bundle-version
34 | 1.0
35 | kind
36 | software
37 | platform-identifier
38 | com.apple.platform.iphoneos
39 | title
40 | Layover
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BE/layover/public/apps/Layover.ipa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/Layover.ipa
--------------------------------------------------------------------------------
/BE/layover/public/apps/images/layover_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/images/layover_1.png
--------------------------------------------------------------------------------
/BE/layover/public/apps/images/layover_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/apps/images/layover_2.png
--------------------------------------------------------------------------------
/BE/layover/public/apps/manifest.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | assets
9 |
10 |
11 | kind
12 | software-package
13 | url
14 | https://layoverapi.shop:3000/apps/Layover.ipa
15 |
16 |
17 | kind
18 | display-image
19 | url
20 | https://layoverapi.shop/apps/images/layover_1.png
21 |
22 |
23 | kind
24 | full-size-image
25 | url
26 | https://layoverapi.shop/apps/images/layover_2.png
27 |
28 |
29 | metadata
30 |
31 | bundle-identifier
32 | kr.codesquad.boostcamp8.Layover
33 | bundle-version
34 | 1.0
35 | kind
36 | software
37 | platform-identifier
38 | com.apple.platform.iphoneos
39 | title
40 | Layover
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/BE/layover/public/iOS.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Layover IPA deploy page
7 |
8 |
9 | Layover IPA deploy page
10 |
11 | Merry Christmas
12 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/BE/layover/public/images/kong.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/BE/layover/public/images/kong.jpeg
--------------------------------------------------------------------------------
/BE/layover/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/BE/layover/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | constructor(private readonly appService: AppService) {}
7 |
8 | @Get()
9 | getHello(): string {
10 | return this.appService.getHello();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BE/layover/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 | import { DatabaseModule } from './database/database.module';
5 | import { OauthModule } from './oauth/oauth.module';
6 | import { ServeStaticModule } from '@nestjs/serve-static';
7 | import { join } from 'path';
8 | import { BoardModule } from './board/board.module';
9 | import { TagModule } from './tag/tag.module';
10 | import { ReportModule } from './report/report.module';
11 | import { LoggingInterceptor } from './utils/logging-interceptor';
12 | import { APP_INTERCEPTOR } from '@nestjs/core';
13 |
14 | @Module({
15 | imports: [
16 | DatabaseModule,
17 | OauthModule,
18 | ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'public') }),
19 | BoardModule,
20 | TagModule,
21 | ReportModule,
22 | ],
23 | controllers: [AppController],
24 | providers: [
25 | AppService,
26 | {
27 | provide: APP_INTERCEPTOR,
28 | useClass: LoggingInterceptor,
29 | },
30 | ],
31 | })
32 | export class AppModule {}
33 |
--------------------------------------------------------------------------------
/BE/layover/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BE/layover/src/board/board.module.ts:
--------------------------------------------------------------------------------
1 | import { Module, forwardRef } from '@nestjs/common';
2 | import { BoardController } from './board.controller';
3 | import { BoardService } from './board.service';
4 | import { DatabaseModule } from '../database/database.module';
5 | import { boardProvider } from './board.provider';
6 | import { MemberModule } from '../member/member.module';
7 | import { TagModule } from '../tag/tag.module';
8 | import { BoardRepository } from './board.repository';
9 |
10 | @Module({
11 | imports: [DatabaseModule, forwardRef(() => MemberModule), TagModule],
12 | providers: [BoardService, BoardRepository, ...boardProvider],
13 | exports: [BoardService],
14 | controllers: [BoardController],
15 | })
16 | export class BoardModule {}
17 |
--------------------------------------------------------------------------------
/BE/layover/src/board/board.provider.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from 'typeorm';
2 | import { Board } from './board.entity';
3 |
4 | export const boardProvider = [
5 | {
6 | provide: 'BOARD_REPOSITORY',
7 | useFactory: (dataSource: DataSource) => dataSource.getRepository(Board),
8 | inject: ['DATA_SOURCE'],
9 | },
10 | ];
11 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/board-pre-signed-url.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
3 |
4 | export class BoardPreSignedUrlDto {
5 | @ApiProperty({
6 | example: 1,
7 | description: '업로드할 동영상의 게시글 id',
8 | })
9 | @IsNumber()
10 | @IsNotEmpty()
11 | readonly boardId: number;
12 |
13 | @ApiProperty({
14 | example: 'mp4',
15 | description: '업로드할 동영상 타입',
16 | })
17 | @IsString()
18 | @IsNotEmpty()
19 | readonly filetype: string;
20 | }
21 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/boards-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { MemberInfosResDto } from '../../member/dtos/member-infos-res.dto';
2 | import { BoardResDto } from './board-res-dto';
3 | import { ApiProperty } from '@nestjs/swagger';
4 |
5 | export class BoardsResDto {
6 | @ApiProperty({ type: () => MemberInfosResDto })
7 | member: MemberInfosResDto;
8 |
9 | @ApiProperty({ type: () => BoardResDto })
10 | board: BoardResDto;
11 |
12 | @ApiProperty({
13 | example: ['tag1', 'tag2'],
14 | description: '게시글의 태그',
15 | })
16 | tag: string[];
17 |
18 | constructor(member: MemberInfosResDto, board: BoardResDto, tag: string[]) {
19 | this.member = member;
20 | this.board = board;
21 | this.tag = tag;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/create-board-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class CreateBoardResDto {
4 | @ApiProperty({
5 | example: 1,
6 | description: '게시글 id',
7 | })
8 | readonly id: number;
9 |
10 | @ApiProperty({
11 | example: '제목',
12 | description: '게시글 제목',
13 | })
14 | readonly title: string;
15 |
16 | @ApiProperty({
17 | example: '내용',
18 | description: '게시글 내용',
19 | })
20 | readonly content: string;
21 |
22 | @ApiProperty({
23 | example: '37.12310530',
24 | description: '위도',
25 | })
26 | readonly latitude: number;
27 |
28 | @ApiProperty({
29 | example: '127.12310530',
30 | description: '경도',
31 | })
32 | readonly longitude: number;
33 |
34 | @ApiProperty({
35 | example: ['부산', '광안리', '바다'],
36 | description: '사용자가 작성한 태그들',
37 | })
38 | readonly tag: string[];
39 |
40 | constructor(id: number, title: string, content: string, latitude: number, longitude: number, tag: string[]) {
41 | this.id = id;
42 | this.title = title;
43 | this.content = content;
44 | this.latitude = latitude;
45 | this.longitude = longitude;
46 | this.tag = tag;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/create-board.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsOptional, IsString } from 'class-validator';
3 |
4 | export class CreateBoardDto {
5 | @ApiProperty({
6 | example: '부산 광안리',
7 | description: '제목',
8 | })
9 | readonly title: string;
10 |
11 | @ApiProperty({
12 | example: 'chilling at the beach~',
13 | description: '내용',
14 | required: false,
15 | })
16 | @IsString()
17 | @IsOptional()
18 | content?: string;
19 |
20 | @ApiProperty({
21 | example: '37.0532156213',
22 | description: '게시글 위도',
23 | })
24 | latitude: number;
25 |
26 | @ApiProperty({
27 | example: '37.0532156213',
28 | description: '게시글 경도',
29 | })
30 | longitude: number;
31 |
32 | @ApiProperty({
33 | example: ['부산', '광안리', '바다'],
34 | description: '사용자가 작성한 태그들',
35 | required: false,
36 | })
37 | @IsOptional()
38 | tag?: string[];
39 |
40 | constructor(title: string, content: string, latitude: number, longitude: number, tag: string[]) {
41 | this.title = title;
42 | this.content = content;
43 | this.latitude = latitude;
44 | this.longitude = longitude;
45 | this.tag = tag;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/encoding-callback.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class EncodingCallbackDto {
5 | @ApiProperty({
6 | example: 'uusu123135131-123143ads-213',
7 | description: '동영상 파일 이름',
8 | })
9 | @IsString()
10 | readonly filename: string;
11 |
12 | @ApiProperty({
13 | example: 'RUNNING',
14 | description: '입력 파일의 인코딩 상태',
15 | })
16 | @IsString()
17 | readonly status: string;
18 |
19 | @ApiProperty({
20 | example: 'ncloud.video.download.com/sfsdsdsdsfsd',
21 | description: 'm3u8 master 링크',
22 | })
23 | readonly filePath?: string;
24 | }
25 |
--------------------------------------------------------------------------------
/BE/layover/src/board/dtos/upload-callback.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class UploadCallbackDto {
5 | @ApiProperty({
6 | example: 'sample.mp4',
7 | description: '업로드된 원본 파일 이름',
8 | })
9 | @IsString()
10 | readonly filename: string;
11 | }
12 |
--------------------------------------------------------------------------------
/BE/layover/src/config.ts:
--------------------------------------------------------------------------------
1 | export const ACCESS_TOKEN_EXP_IN_SECOND = 60 * 60 * 24 * 7;
2 | export const REFRESH_TOKEN_EXP_IN_SECOND = 60 * 60 * 24 * 30;
3 | export const MAX_USERNAME = 20;
4 |
--------------------------------------------------------------------------------
/BE/layover/src/database/database.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { databaseProviders } from './database.provider';
3 | import { ConfigModule } from '@nestjs/config';
4 |
5 | @Module({
6 | imports: [ConfigModule.forRoot()],
7 | providers: [...databaseProviders],
8 | exports: [...databaseProviders],
9 | })
10 | export class DatabaseModule {}
11 |
--------------------------------------------------------------------------------
/BE/layover/src/database/database.provider.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from 'typeorm';
2 |
3 | export const databaseProviders = [
4 | {
5 | provide: 'DATA_SOURCE', // 둘 이상의 provider가 있으면 얘로 구분됨. 따로 작성하지 않으면 class 이름이 provider 키가 됨.
6 | useFactory: async () => {
7 | const dataSource = new DataSource({
8 | type: 'mysql',
9 | host: process.env.MYSQL_HOST,
10 | port: Number(process.env.MYSQL_PORT),
11 | username: process.env.MYSQL_USERNAME,
12 | password: process.env.MYSQL_PASSWORD,
13 | database: 'layover_test',
14 | entities: [__dirname + '/../**/*.entity{.ts,.js}'],
15 | synchronize: true,
16 | charset: 'utf8mb4_0900_ai_ci',
17 | extra: {
18 | charset: 'utf8mb4_0900_ai_ci',
19 | },
20 | });
21 |
22 | return dataSource.initialize();
23 | },
24 | },
25 | ];
26 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/check-username-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class CheckUsernameResDto {
4 | @ApiProperty({
5 | example: 'true',
6 | description: '닉네임 검증 결과 bool 값',
7 | })
8 | isValid: boolean;
9 |
10 | constructor(isValid: boolean) {
11 | this.isValid = isValid;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/check-username.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class CheckUsernameDto {
4 | @ApiProperty({
5 | example: 'hwani',
6 | description: '유효성을 검증하거나 변경하고자 하는 닉네임',
7 | })
8 | readonly username: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/delete-member-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class DeleteMemberResDto {
4 | @ApiProperty({
5 | example: 'hooni',
6 | description: '삭제된 멤버의 닉네임',
7 | })
8 | username: string;
9 |
10 | constructor(username: string) {
11 | this.username = username;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/introduce-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class IntroduceResDto {
4 | @ApiProperty({
5 | example: 'Hi, my name is hwani',
6 | description: '새로운 자기소개',
7 | })
8 | introduce: string;
9 |
10 | constructor(introduce: string) {
11 | this.introduce = introduce;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/introduce.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class IntroduceDto {
4 | @ApiProperty({
5 | example: 'Hi, my name is hwani',
6 | description: '새로운 자기소개',
7 | })
8 | readonly introduce: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/member-infos-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class MemberInfosResDto {
4 | @ApiProperty({
5 | example: 221,
6 | description: '요청한 회원의 id 값(해당 회원을 유일하게 구분하는 값)',
7 | })
8 | id: number;
9 |
10 | @ApiProperty({
11 | example: 'hwani',
12 | description: '요청한 회원의 닉네임',
13 | })
14 | username: string;
15 |
16 | @ApiProperty({
17 | example: 'Hi, my name is hwani',
18 | description: '요청한 회원의 자기소개',
19 | })
20 | introduce: string;
21 |
22 | @ApiProperty({
23 | example: 'https://layover-profile-image.kr.obj...',
24 | description: '요청한 회원의 프로필 이미지를 다운받을 수 있는 url',
25 | })
26 | profile_image_url: string | null;
27 |
28 | constructor(id: number, username: string, introduce: string, profile_image_url: string | null) {
29 | this.id = id;
30 | this.username = username;
31 | this.introduce = introduce;
32 | this.profile_image_url = profile_image_url;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/profile-pre-signed-url.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class ProfilePreSignedUrlDto {
4 | @ApiProperty({
5 | example: 'jpeg',
6 | description: '업로드할 영상 이름과 타입',
7 | })
8 | readonly filetype: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/username-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class UsernameResDto {
4 | @ApiProperty({
5 | example: 'hwani2',
6 | description: '변경된 닉네임 값',
7 | })
8 | username: string;
9 |
10 | constructor(username: string) {
11 | this.username = username;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/src/member/dtos/username.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class UsernameDto {
4 | @ApiProperty({
5 | example: 'hwani1',
6 | description: '변경 변경하고자 하는 닉네임',
7 | })
8 | readonly username: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/member/member.entity.ts:
--------------------------------------------------------------------------------
1 | import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
2 |
3 | export type memberStatus = 'EXIST' | 'DELETED';
4 |
5 | @Entity()
6 | export class Member {
7 | @PrimaryGeneratedColumn('increment')
8 | id: number;
9 |
10 | @Column({ nullable: false, length: 20 })
11 | username: string;
12 |
13 | @Column({ nullable: false, length: 255 })
14 | profile_image_key: string;
15 |
16 | @Column({ nullable: false, length: 100 })
17 | introduce: string;
18 |
19 | @Column({ nullable: false, length: 255 })
20 | provider: string;
21 |
22 | @Column({ nullable: false, length: 255 })
23 | hash: string;
24 |
25 | @Column({
26 | nullable: false,
27 | type: 'datetime',
28 | default: () => 'CURRENT_TIMESTAMP',
29 | })
30 | date_created: Date;
31 |
32 | @Column({
33 | nullable: false,
34 | length: 20,
35 | })
36 | status: memberStatus;
37 |
38 | constructor(
39 | id: number,
40 | username: string,
41 | profile_image_key: string,
42 | introduce: string,
43 | provider: string,
44 | hash: string,
45 | date_created: Date,
46 | status: memberStatus,
47 | ) {
48 | this.id = id;
49 | this.username = username;
50 | this.profile_image_key = profile_image_key;
51 | this.introduce = introduce;
52 | this.provider = provider;
53 | this.hash = hash;
54 | this.date_created = date_created;
55 | this.status = status;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/BE/layover/src/member/member.module.ts:
--------------------------------------------------------------------------------
1 | import { Module, forwardRef } from '@nestjs/common';
2 | import { DatabaseModule } from '../database/database.module';
3 | import { memberProviders } from './member.providers';
4 | import { MemberService } from './member.service';
5 | import { MemberController } from './member.controller';
6 | import { MemberRepository } from './member.repository';
7 | import { BoardModule } from 'src/board/board.module';
8 | import { ReportModule } from 'src/report/report.module';
9 | import { RedisModule } from 'src/redis/redis.module';
10 |
11 | @Module({
12 | imports: [DatabaseModule, forwardRef(() => BoardModule), forwardRef(() => ReportModule), RedisModule],
13 | providers: [...memberProviders, MemberService, MemberRepository],
14 | exports: [MemberService],
15 | controllers: [MemberController],
16 | })
17 | export class MemberModule {}
18 |
--------------------------------------------------------------------------------
/BE/layover/src/member/member.providers.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from 'typeorm';
2 | import { Member } from './member.entity';
3 |
4 | export const memberProviders = [
5 | {
6 | provide: 'MEMBER_REPOSITORY',
7 | useFactory: (dataSource: DataSource) => dataSource.getRepository(Member),
8 | inject: ['DATA_SOURCE'],
9 | },
10 | ];
11 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/apple-login.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class AppleLoginDto {
4 | @ApiProperty({
5 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
6 | description: '애플 아이덴티티 토큰',
7 | })
8 | readonly identityToken: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/apple-signup.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class AppleSignupDto {
4 | @ApiProperty({
5 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
6 | description: '애플 아이덴티티 토큰',
7 | })
8 | readonly identityToken: string;
9 |
10 | @ApiProperty({
11 | example: 'myUsername',
12 | description: '설정할 유저 닉네임',
13 | })
14 | readonly username: string;
15 | }
16 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/check-signup-res-dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class CheckSignupResDto {
4 | @ApiProperty({
5 | example: 'true',
6 | description: '해당 계정이 이미 존재하는지 여부 boolean 값',
7 | })
8 | isAlreadyExist: boolean;
9 |
10 | constructor(isAlreadyExist: boolean) {
11 | this.isAlreadyExist = isAlreadyExist;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/kakao-login.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class KakaoLoginDto {
4 | @ApiProperty({
5 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
6 | description: '카카오 액세스 토큰',
7 | })
8 | readonly accessToken: string;
9 | }
10 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/kakao-signup.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class KakaoSignupDto {
4 | @ApiProperty({
5 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
6 | description: '카카오 액세스 토큰',
7 | })
8 | readonly accessToken: string;
9 |
10 | @ApiProperty({
11 | example: 'myUsername',
12 | description: '설정할 유저 닉네임',
13 | })
14 | readonly username: string;
15 | }
16 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/dtos/token-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class TokenResDto {
4 | @ApiProperty({
5 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
6 | description: 'JWT Access 토큰',
7 | })
8 | accessToken: string;
9 |
10 | @ApiProperty({
11 | example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
12 | description: 'JWT Refresh 토큰',
13 | })
14 | refreshToken: string;
15 |
16 | constructor(accessToken: string, refreshToken: string) {
17 | this.accessToken = accessToken;
18 | this.refreshToken = refreshToken;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/oauth.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { OauthController } from './oauth.controller';
3 | import { HttpModule } from '@nestjs/axios';
4 | import { OauthService } from './oauth.service';
5 | import { MemberModule } from 'src/member/member.module';
6 | import { JwtModule } from '@nestjs/jwt';
7 | import { RedisModule } from 'src/redis/redis.module';
8 | import { ConfigModule } from '@nestjs/config';
9 | import { BoardModule } from 'src/board/board.module';
10 |
11 | @Module({
12 | imports: [
13 | ConfigModule.forRoot(),
14 | HttpModule,
15 | MemberModule,
16 | BoardModule,
17 | JwtModule.register({
18 | signOptions: { algorithm: 'HS256' },
19 | secret: process.env.JWT_SECRET_KEY,
20 | }),
21 | RedisModule,
22 | ],
23 | controllers: [OauthController],
24 | providers: [OauthService],
25 | })
26 | export class OauthModule {}
27 |
--------------------------------------------------------------------------------
/BE/layover/src/oauth/oauth.repository.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class OauthRepository {}
5 |
--------------------------------------------------------------------------------
/BE/layover/src/pipes/custom-header.decorator.ts:
--------------------------------------------------------------------------------
1 | import { ExecutionContext, createParamDecorator } from '@nestjs/common';
2 |
3 | export const CustomHeader = createParamDecorator((data: string, ctx: ExecutionContext) => {
4 | const req = ctx.switchToHttp().getRequest();
5 | return data ? req.headers[data] : req.headers;
6 | });
7 |
--------------------------------------------------------------------------------
/BE/layover/src/redis/redis.module.ts:
--------------------------------------------------------------------------------
1 | import { Global, Module } from '@nestjs/common';
2 | import { redisProvider } from './redis.provider';
3 |
4 | @Global()
5 | @Module({
6 | providers: [...redisProvider],
7 | exports: [...redisProvider],
8 | })
9 | export class RedisModule {}
10 |
--------------------------------------------------------------------------------
/BE/layover/src/redis/redis.provider.ts:
--------------------------------------------------------------------------------
1 | import { createClient } from 'redis';
2 |
3 | export const redisProvider = [
4 | {
5 | provide: 'REDIS_CLIENT',
6 | useFactory: async (): Promise> => {
7 | const client = await createClient({
8 | url: `redis://${process.env.REDIS_USERNAME}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
9 | })
10 | .on('error', (err) => console.log('Redis Client Error', err))
11 | .connect();
12 | return client;
13 | },
14 | },
15 | {
16 | provide: 'REDIS_FOR_BLACKLIST_CLIENT',
17 | useFactory: async (): Promise> => {
18 | const client = await createClient({
19 | url: `redis://${process.env.REDIS_FOR_BLACKLIST_USERNAME}:${process.env.REDIS_FOR_BLACKLIST_PASSWORD}@${process.env.REDIS_FOR_BLACKLIST_HOST}:${process.env.REDIS_FOR_BLACKLIST_PORT}`,
20 | })
21 | .on('error', (err) => console.log('Redis Client Error', err))
22 | .connect();
23 | return client;
24 | },
25 | },
26 | ];
27 |
--------------------------------------------------------------------------------
/BE/layover/src/report/dtos/report-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class ReportResDto {
4 | @ApiProperty({
5 | example: 221,
6 | description: '신고한 멤버의 id',
7 | })
8 | memberId: number;
9 |
10 | @ApiProperty({
11 | example: 5,
12 | description: '신고 게시글 id',
13 | })
14 | boardId: number;
15 |
16 | @ApiProperty({
17 | example: '청소년에게 유해한 내용이에요',
18 | description: '신고 유형',
19 | })
20 | reportType: string;
21 |
22 | constructor(memberId: number, boardId: number, reportType: string) {
23 | this.memberId = memberId;
24 | this.boardId = boardId;
25 | this.reportType = reportType;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/BE/layover/src/report/dtos/report.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class ReportDto {
4 | @ApiProperty({
5 | example: 5,
6 | description: '신고 게시글 id',
7 | })
8 | readonly boardId: number;
9 |
10 | @ApiProperty({
11 | example: '청소년에게 유해한 내용이에요',
12 | description: '신고 유형',
13 | })
14 | readonly reportType: string;
15 | }
16 |
--------------------------------------------------------------------------------
/BE/layover/src/report/report.entity.ts:
--------------------------------------------------------------------------------
1 | import { Board } from 'src/board/board.entity';
2 | import { Member } from 'src/member/member.entity';
3 | import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
4 |
5 | @Entity()
6 | export class Report {
7 | @PrimaryGeneratedColumn('increment')
8 | id: number;
9 |
10 | @ManyToOne(() => Member, (member) => member.id)
11 | @JoinColumn({ name: 'member_id' })
12 | member: Member;
13 |
14 | @ManyToOne(() => Board, (board) => board.id)
15 | @JoinColumn({ name: 'board_id' })
16 | board: Board;
17 |
18 | @Column({ nullable: false, length: 255 })
19 | report_type: string;
20 | }
21 |
--------------------------------------------------------------------------------
/BE/layover/src/report/report.module.ts:
--------------------------------------------------------------------------------
1 | import { Module, forwardRef } from '@nestjs/common';
2 | import { ReportController } from './report.controller';
3 | import { reportProviders } from './report.provider';
4 | import { ReportService } from './report.service';
5 | import { MemberModule } from 'src/member/member.module';
6 | import { DatabaseModule } from 'src/database/database.module';
7 | import { BoardModule } from 'src/board/board.module';
8 |
9 | @Module({
10 | imports: [DatabaseModule, forwardRef(() => MemberModule), BoardModule],
11 | controllers: [ReportController],
12 | providers: [...reportProviders, ReportService],
13 | exports: [ReportService],
14 | })
15 | export class ReportModule {}
16 |
--------------------------------------------------------------------------------
/BE/layover/src/report/report.provider.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from 'typeorm';
2 | import { Report } from './report.entity';
3 |
4 | export const reportProviders = [
5 | {
6 | provide: 'REPORT_REPOSITORY',
7 | useFactory: (dataSource: DataSource) => dataSource.getRepository(Report),
8 | inject: ['DATA_SOURCE'],
9 | },
10 | ];
11 |
--------------------------------------------------------------------------------
/BE/layover/src/report/report.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable } from '@nestjs/common';
2 | import { MemberService } from 'src/member/member.service';
3 | import { Report } from './report.entity';
4 | import { Repository } from 'typeorm';
5 | import { BoardService } from 'src/board/board.service';
6 | import { ReportResDto } from './dtos/report-res.dto';
7 |
8 | @Injectable()
9 | export class ReportService {
10 | constructor(
11 | @Inject('REPORT_REPOSITORY') private readonly reportRepository: Repository,
12 | private readonly memberService: MemberService,
13 | private readonly boardService: BoardService,
14 | ) {}
15 |
16 | async createReport(memberId: number, boardId: number, reportType: string): Promise {
17 | const member = await this.memberService.getMemberById(memberId);
18 | const board = await this.boardService.getBoardById(boardId);
19 | await this.reportRepository.insert({
20 | member: member,
21 | board: board,
22 | report_type: reportType,
23 | });
24 | return new ReportResDto(member.id, board.id, reportType);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/BE/layover/src/report/report.swagger.ts:
--------------------------------------------------------------------------------
1 | import { HttpStatus } from '@nestjs/common';
2 | import { getSchemaPath } from '@nestjs/swagger';
3 | import { ReportResDto } from './dtos/report-res.dto';
4 |
5 | export const REPORT_SWAGGER = {
6 | RECEIVE_REPORT_SUCCESS: {
7 | status: HttpStatus.OK,
8 | description: '신고 요청 성공',
9 | schema: {
10 | type: 'object',
11 | properties: {
12 | message: { type: 'string', example: '요청이 성공적으로 처리되었습니다.' },
13 | statusCode: { type: 'number', example: HttpStatus.OK },
14 | data: { $ref: getSchemaPath(ReportResDto) },
15 | },
16 | },
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/BE/layover/src/response/custom-response.ts:
--------------------------------------------------------------------------------
1 | import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common';
2 | import { Response } from 'express';
3 | import { ECustomCode } from './ecustom-code.jenum';
4 | import { ApiProperty } from '@nestjs/swagger';
5 |
6 | export class CustomResponse extends HttpException {
7 | @ApiProperty({
8 | description: '응답 데이터',
9 | })
10 | data?: any;
11 |
12 | constructor(customException: ECustomCode, data?: any) {
13 | super(customException.message, customException.statusCode);
14 | this.data = data;
15 | }
16 | }
17 |
18 | @Catch()
19 | export class GlobalExceptionFilter implements ExceptionFilter {
20 | catch(exception: any, host: ArgumentsHost) {
21 | const ctx = host.switchToHttp();
22 | const response: Response = ctx.getResponse();
23 |
24 | let statusCode: HttpStatus;
25 |
26 | if (exception instanceof CustomResponse) {
27 | statusCode = exception.getStatus();
28 | } else if (exception instanceof HttpException) {
29 | statusCode = exception.getStatus();
30 | } else {
31 | statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
32 | }
33 |
34 | response.status(statusCode).json({
35 | message: exception.message,
36 | statusCode: statusCode,
37 | data: exception.data,
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/BE/layover/src/tag/tag.entity.ts:
--------------------------------------------------------------------------------
1 | import { Board } from '../board/board.entity';
2 | import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
3 |
4 | @Entity()
5 | export class Tag {
6 | @PrimaryGeneratedColumn('increment')
7 | id: number;
8 |
9 | @ManyToOne(() => Board, (board) => board.id)
10 | @JoinColumn({ name: 'board_id' })
11 | board: Board;
12 |
13 | @Column({ nullable: false })
14 | tagname: string;
15 | }
16 |
--------------------------------------------------------------------------------
/BE/layover/src/tag/tag.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TagService } from './tag.service';
3 | import { tagProvider } from './tag.provider';
4 | import { DatabaseModule } from '../database/database.module';
5 | import { TagRepository } from './tag.repository';
6 |
7 | @Module({
8 | imports: [DatabaseModule],
9 | providers: [...tagProvider, TagService, TagRepository],
10 | exports: [TagService],
11 | })
12 | export class TagModule {}
13 |
--------------------------------------------------------------------------------
/BE/layover/src/tag/tag.provider.ts:
--------------------------------------------------------------------------------
1 | import { DataSource } from 'typeorm';
2 | import { Tag } from './tag.entity';
3 |
4 | export const tagProvider = [
5 | {
6 | provide: 'TAG_REPOSITORY',
7 | useFactory: (dataSource: DataSource) => dataSource.getRepository(Tag),
8 | inject: ['DATA_SOURCE'],
9 | },
10 | ];
11 |
--------------------------------------------------------------------------------
/BE/layover/src/tag/tag.repository.ts:
--------------------------------------------------------------------------------
1 | import { Inject } from '@nestjs/common';
2 | import { Repository } from 'typeorm';
3 | import { Tag } from './tag.entity';
4 | import { Board } from '../board/board.entity';
5 |
6 | export class TagRepository {
7 | constructor(@Inject('TAG_REPOSITORY') private tagRepository: Repository) {}
8 |
9 | async saveTag(board: Board, tagname: string) {
10 | await this.tagRepository.save({ board: board, tagname: tagname });
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BE/layover/src/tag/tag.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { Board } from '../board/board.entity';
3 | import { TagRepository } from './tag.repository';
4 |
5 | @Injectable()
6 | export class TagService {
7 | constructor(private tagRepository: TagRepository) {}
8 |
9 | async createTag(board: Board, tagname: string): Promise {
10 | await this.tagRepository.saveTag(board, tagname);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BE/layover/src/utils/hashUtils.ts:
--------------------------------------------------------------------------------
1 | import { createHash, createHmac } from 'crypto';
2 |
3 | export function hashSHA256(input: string): string {
4 | const hash = createHash('sha256');
5 | hash.update(input);
6 | return hash.digest('hex');
7 | }
8 |
9 | export function hashHMACSHA256(message: string, secret: string): string {
10 | const hmac = createHmac('sha256', secret);
11 | hmac.update(message);
12 |
13 | const signature = hmac.digest('base64url');
14 | return signature;
15 | }
16 |
--------------------------------------------------------------------------------
/BE/layover/src/utils/interfaces/token.payload.d.ts:
--------------------------------------------------------------------------------
1 | export interface tokenPayload {
2 | iss: string;
3 | exp: number;
4 | sub: string;
5 | aud: string;
6 | nbf: number;
7 | iat: number;
8 | jti: string;
9 | memberHash: string;
10 | memberId: number;
11 | }
12 |
--------------------------------------------------------------------------------
/BE/layover/src/utils/my-logger.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from '@nestjs/common';
2 | import { createLogger, format, transports } from 'winston';
3 | import * as moment from 'moment-timezone';
4 |
5 | export class MyLogger extends Logger {
6 | private winstonLogger = createLogger({
7 | format: format.combine(
8 | format.timestamp({
9 | format: () => moment().tz('Asia/Seoul').format(),
10 | }),
11 | format.printf(({ level, message, timestamp }) => `${timestamp} ${level}: ${message}`),
12 | ),
13 | transports: [new transports.File({ filename: 'logs.log' })],
14 | });
15 |
16 | log(message: string) {
17 | super.log(message);
18 | this.winstonLogger.info(message);
19 | }
20 |
21 | error(message: string) {
22 | super.error(message);
23 | this.winstonLogger.error(message);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/BE/layover/src/utils/pre-signed-url-res.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class PreSignedUrlResDto {
4 | @ApiProperty({
5 | example: 'https://layover-original-video.s3.amazonaws.com/14bb1a79093f5b9443e9b8105.....',
6 | description: '동영상을 업로드 하기 위해 요청할 링크',
7 | })
8 | readonly preSignedUrl: string;
9 |
10 | constructor(preSignedUrl: string) {
11 | this.preSignedUrl = preSignedUrl;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BE/layover/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { AppModule } from './../src/app.module';
5 |
6 | describe('AppController (e2e)', () => {
7 | let app: INestApplication;
8 |
9 | beforeEach(async () => {
10 | const moduleFixture: TestingModule = await Test.createTestingModule({
11 | imports: [AppModule],
12 | }).compile();
13 |
14 | app = moduleFixture.createNestApplication();
15 | await app.init();
16 | });
17 |
18 | it('/ (GET)', () => {
19 | return request(app.getHttpServer()).get('/').expect(200).expect('Hello World!');
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/BE/layover/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": "../",
4 | "modulePaths": [""],
5 | "testEnvironment": "node",
6 | "testRegex": ".e2e-spec.ts$",
7 | "transform": {
8 | "^.+\\.(t|j)s$": "ts-jest"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BE/layover/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/BE/layover/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "ES2021",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true,
14 | "skipLibCheck": true,
15 | "strictNullChecks": false,
16 | "noImplicitAny": false,
17 | "strictBindCallApply": false,
18 | "forceConsistentCasingInFileNames": false,
19 | "noFallthroughCasesInSwitch": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS/Layover/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - todo
3 | - nesting
4 |
5 | line_length: 200
6 | excluded:
7 | - Layover/AppDelegate.swift
8 | - Layover/SceneDelegate.swift
9 |
10 | identifier_name:
11 | excluded:
12 | - ui
13 | - id
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/DesignSystem/LOSlider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LOSlider.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 11/15/23.
6 | //
7 |
8 | import UIKit
9 |
10 | final class LOSlider: UISlider {
11 | static let loSliderHeight: CGFloat = 10
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | setUI()
16 | }
17 |
18 | required init?(coder: NSCoder) {
19 | super.init(coder: coder)
20 | setUI()
21 | }
22 |
23 | override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
24 | setThumbImage(UIImage.loSelectedThumb, for: .normal)
25 | return true
26 | }
27 |
28 | override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
29 | setThumbImage(UIImage.loNormalThumb, for: .normal)
30 | }
31 |
32 | private func setUI() {
33 | self.minimumTrackTintColor = .primaryPurple
34 | setThumbImage(UIImage.loNormalThumb, for: .normal)
35 | self.minimumValue = 0
36 | self.maximumValue = 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/DesignSystem/LOTextLabel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LOTextLabel.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 1/25/24.
6 | // Copyright © 2024 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class LOTextLabel: UILabel {
12 |
13 | private var padding = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
14 |
15 | convenience init(padding: UIEdgeInsets) {
16 | self.init()
17 | self.padding = padding
18 | setUI()
19 | }
20 |
21 | override func drawText(in rect: CGRect) {
22 | super.drawText(in: rect.inset(by: padding))
23 | }
24 |
25 | override var intrinsicContentSize: CGSize {
26 | var contentSize = super.intrinsicContentSize
27 | contentSize.height += padding.top + padding.bottom
28 | contentSize.width += padding.left + padding.right
29 |
30 | return contentSize
31 | }
32 |
33 | private func setUI() {
34 | layer.cornerRadius = 8
35 | layer.borderWidth = 1
36 | layer.borderColor = UIColor.grey500.cgColor
37 | backgroundColor = UIColor.clear
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/AVFileType+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AVFileType+.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/14.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import AVFoundation
10 |
11 | extension AVFileType {
12 | static func from(_ url: URL) -> AVFileType? {
13 | let pathExtension = url.pathExtension
14 | switch pathExtension {
15 | case "mp4":
16 | return .mp4
17 | case "mov":
18 | return .mov
19 | case "m4v":
20 | return .m4v
21 | default:
22 | return nil
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/Notification.Name+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notification.Name+.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/27/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Notification.Name {
12 | static let refreshTokenDidExpired = Notification.Name("refreshTokenDidExpired")
13 | static let uploadTaskStart = Notification.Name("uploadTaskStart")
14 | static let progressChanged = Notification.Name("progressChanged")
15 | static let uploadTaskDidComplete = Notification.Name("uploadTaskDidComplete")
16 | static let uploadTaskDidFail = Notification.Name("uploadTaskDidFail")
17 | }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/OSLog+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OSLog+.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/14/23.
6 | //
7 |
8 | import OSLog
9 |
10 | extension OSLog {
11 | private static var subsystem = Bundle.main.bundleIdentifier ?? "kr.codesquad.boostcamp8.Layover"
12 |
13 | // add more OSLog if you need.
14 | static let ui = OSLog(subsystem: subsystem, category: "UI")
15 | static let data = OSLog(subsystem: subsystem, category: "Data")
16 | }
17 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/Sequence+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Sequence+.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/30/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | extension Sequence {
10 | func asyncMap(
11 | _ transform: (Element) async throws -> T
12 | ) async rethrows -> [T] {
13 | var values = [T]()
14 |
15 | for element in self {
16 | try await values.append(transform(element))
17 | }
18 |
19 | return values
20 | }
21 |
22 | func asyncCompactMap(
23 | _ transform: (Element) async throws -> T?
24 | ) async rethrows -> [T] {
25 | var values = [T]()
26 |
27 | for element in self {
28 | if let value = try await transform(element) {
29 | values.append(value)
30 | }
31 | }
32 |
33 | return values
34 | }
35 |
36 | func concurrentMap(
37 | _ transform: @escaping (Element) async throws -> T
38 | ) async throws -> [T] {
39 | let tasks = map { element in
40 | Task {
41 | try await transform(element)
42 | }
43 | }
44 |
45 | return try await tasks.asyncMap { task in
46 | try await task.value
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/UICollectionViewLayout+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionViewLayout+.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/19.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension NSCollectionLayoutSection {
12 | static func makeCarouselSection(groupWidthDimension: CGFloat) -> NSCollectionLayoutSection {
13 | let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
14 | heightDimension: .fractionalHeight(1.0))
15 | let item = NSCollectionLayoutItem(layoutSize: itemSize)
16 | let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(groupWidthDimension),
17 | heightDimension: .fractionalHeight(1.0))
18 | let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
19 | return NSCollectionLayoutSection(group: group)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/UIView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/15/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 |
13 | static var identifier: String {
14 | return String(describing: self)
15 | }
16 |
17 | func addSubviews(_ views: UIView...) {
18 | views.forEach { addSubview($0) }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/UIViewController+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/26.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIViewController {
12 | var screenSize: CGRect {
13 | guard let window = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
14 | return view.window?.windowScene?.screen.bounds ?? CGRect(x: 0, y: 0, width: 375, height: 667)
15 | }
16 | return window.screen.bounds
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/URL+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/14/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension URL {
12 | func changeScheme(to: String) -> URL {
13 | var components = URLComponents(url: self, resolvingAgainstBaseURL: false)
14 | components?.scheme = to
15 | return components?.url ?? self
16 | }
17 |
18 | var customHLSURL: URL {
19 | changeScheme(to: "lhls")
20 | }
21 |
22 | var originHLSURL: URL {
23 | changeScheme(to: "https")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Extensions/URLSession+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLSession+.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/24.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension URLSession {
12 | static func initMockSession(configuration: URLSessionConfiguration = .ephemeral) -> URLSession {
13 | let configuration = URLSessionConfiguration.default
14 | configuration.protocolClasses = [MockURLProtocol.self]
15 | let urlSession = URLSession.init(configuration: configuration)
16 | return urlSession
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BASE_URL
6 | $(BASE_URL)
7 | CFBundleURLTypes
8 |
9 |
10 | CFBundleTypeRole
11 | Editor
12 | CFBundleURLSchemes
13 |
14 | kakao$(KAKAO_APP_KEY)
15 |
16 |
17 |
18 | KAKAO_APP_KEY
19 | $(KAKAO_APP_KEY)
20 | LSApplicationQueriesSchemes
21 |
22 | kakaoplus
23 | kakaokompassauth
24 | kakaolink
25 |
26 | UIAppFonts
27 |
28 | Dashboard-Regular.ttf
29 | Pretendard-Bold.ttf
30 | Pretendard-Regular.ttf
31 | Pretendard-SemiBold.ttf
32 |
33 | UIApplicationSceneManifest
34 |
35 | UIApplicationSupportsMultipleScenes
36 |
37 | UISceneConfigurations
38 |
39 | UIWindowSceneSessionRoleApplication
40 |
41 |
42 | UISceneConfigurationName
43 | Default Configuration
44 | UISceneDelegateClassName
45 | $(PRODUCT_MODULE_NAME).SceneDelegate
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 | DerivedData/
6 | .swiftpm/configuration/registries.json
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 | .netrc
9 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.9
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "LOImageCacher",
8 | platforms: [
9 | .iOS(.v13)
10 | ],
11 | products: [
12 | // Products define the executables and libraries a package produces, making them visible to other packages.
13 | .library(
14 | name: "LOImageCacher",
15 | targets: ["LOImageCacher"])
16 | ],
17 | targets: [
18 | // Targets are the basic building blocks of a package, defining a module or a test suite.
19 | // Targets can depend on other targets in this package and products from dependencies.
20 | .target(
21 | name: "LOImageCacher"),
22 | .testTarget(
23 | name: "LOImageCacherTests",
24 | dependencies: ["LOImageCacher"])
25 | ]
26 | )
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/Sources/LOImageCacher/ImageView + LOImageCacherWrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageView + LOImageCacherWrapper.swift
3 | //
4 | //
5 | // Created by kong on 2024/01/17.
6 | //
7 |
8 | import UIKit
9 |
10 | // MARK: - Extensions
11 |
12 | extension UIImageView: LOImageCacherCompatible { }
13 |
14 | extension LOImageCacherWrapper where Base: UIImageView {
15 |
16 | public func setImage(with url: URL) {
17 | Task {
18 | if let data = await LOImageFetcher.shared.fetchImage(from: url) {
19 | await updateImage(data)
20 | }
21 | }
22 | }
23 |
24 | @MainActor
25 | private func updateImage(_ data: Data) {
26 | self.base.image = UIImage(data: data)
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/Sources/LOImageCacher/LOImageCacher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LOImageCacher.swift
3 | //
4 | //
5 | // Created by kong on 2024/01/17.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct LOImageCacherWrapper {
11 |
12 | // MARK: - Properties
13 |
14 | public let base: Base
15 |
16 | // MARK: - Initializers
17 |
18 | public init(base: Base) {
19 | self.base = base
20 | }
21 | }
22 |
23 | public protocol LOImageCacherCompatible: AnyObject { }
24 |
25 | extension LOImageCacherCompatible {
26 |
27 | // swiftlint:disable identifier_name
28 | public var lo: LOImageCacherWrapper {
29 | LOImageCacherWrapper(base: self)
30 | }
31 | // swiftlint:enable identifier_name
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/Sources/LOImageCacher/LOImageFetcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LOImageFetcher.swift
3 | //
4 | //
5 | // Created by kong on 2024/01/17.
6 | //
7 |
8 | import UIKit
9 |
10 | final class LOImageFetcher {
11 |
12 | typealias ImageCacheStorage = Storage
13 |
14 | // MARK: - Properties
15 |
16 | static let shared = LOImageFetcher()
17 | private let storage: any ImageCacheStorage
18 | private let session: URLSession
19 |
20 | // MARK: - Initializer
21 |
22 | private init(storage: any ImageCacheStorage = LOCacheStorage(),
23 | session: URLSession = .shared) {
24 | self.storage = storage
25 | self.session = session
26 | }
27 |
28 | // MARK: - Methods
29 |
30 | func fetchImage(from url: URL) async -> Data? {
31 | let key = url.lastPathComponent
32 | guard let storageData = storage.retrieve(forKey: key) else {
33 | if let (fetchedData, _) = try? await session.data(from: url) {
34 | storage.store(fetchedData, forKey: key)
35 | storage.storeToDisk(fetchedData, forKey: key)
36 | return fetchedData
37 | } else {
38 | return nil
39 | }
40 | }
41 | return storageData
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/LOImageCacher/Tests/LOImageCacherTests/LOImageCacherTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import LOImageCacher
3 |
4 | final class LOImageCacherTests: XCTestCase {
5 | func testExample() throws {
6 | // XCTest Documentation
7 | // https://developer.apple.com/documentation/xctest
8 |
9 | // Defining Test Cases and Test Methods
10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Layover.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.applesignin
6 |
7 | Default
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Models/Board.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Board.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/30/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Board {
12 | let identifier: Int
13 | let title: String
14 | let description: String?
15 | let thumbnailImageURL: URL?
16 | let videoURL: URL?
17 | let latitude: Double
18 | let longitude: Double
19 | let status: BoardStatus
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Models/Member.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Member.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/30/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Member {
12 | let identifier: Int
13 | let username: String
14 | let introduce: String?
15 | let profileImageURL: URL?
16 | }
17 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Models/Post.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Post.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/29/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Post {
12 | let member: Member
13 | let board: Board
14 | let tag: [String]
15 | var thumbnailImageData: Data?
16 | }
17 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Models/PostsPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostsPage.swift
3 | // Layover
4 | //
5 | // Created by kong on 2024/02/07.
6 | // Copyright © 2024 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct PostsPage {
12 | let cursor: Int
13 | let posts: [Post]
14 | }
15 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Models/UploadPost.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UploadPost.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/05.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UploadPost {
12 | let title: String
13 | let content: String?
14 | let latitude, longitude: Double
15 | let tag: [String]
16 | let videoURL: URL
17 | }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Common/NetworkError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkError.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/13.
6 | //
7 |
8 | import Foundation
9 |
10 | enum NetworkError: LocalizedError {
11 | case unknown
12 | case components
13 | case urlRequest
14 | case server(ServerError)
15 | case emptyData
16 | case parsing
17 | case decoding(Error)
18 |
19 | var errorDescription: String? {
20 | switch self {
21 | case .unknown: "Unknown Error"
22 | case .components: "URL Components Error"
23 | case .urlRequest: "URL Request Error"
24 | case .server(let serverError): "Server Error: \(serverError)"
25 | case .emptyData: "Empty Data Error"
26 | case .parsing: "Error While Parsing"
27 | case .decoding(let error): "Error While Decoding: \(error)"
28 | }
29 | }
30 | }
31 |
32 | enum ServerError: Int {
33 | case unknown
34 | case badRequest = 400
35 | case unauthorized = 401
36 | case forbidden = 403
37 | case notFound = 404
38 | }
39 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/CheckSignUpDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CheckSignUpDTO.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/6/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct CheckSignUpDTO: Decodable {
12 | let isAlreadyExist: Bool
13 | }
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/CheckUserNameDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CheckUserNameDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/24.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct CheckUserNameDTO: Decodable {
12 | let isValid: Bool
13 | }
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/IntroduceDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntroduceDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/25.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct IntroduceDTO: Codable {
12 | let introduce: String
13 | }
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/LoginDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginDTO.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/23/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct LoginDTO: Decodable {
12 | let accessToken: String
13 | let refreshToken: String
14 | }
15 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/MemberDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemberDTO.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/30/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct MemberDTO: Decodable {
12 | let id: Int
13 | let username, introduce: String
14 | let profileImageURL: String?
15 |
16 | enum CodingKeys: String, CodingKey {
17 | case id, username, introduce
18 | case profileImageURL = "profile_image_url"
19 | }
20 | }
21 |
22 | extension MemberDTO {
23 | func toDomain() -> Member {
24 | var imageURL: URL?
25 | if let profileImageURL {
26 | imageURL = URL(string: profileImageURL)
27 | }
28 |
29 | return Member(
30 | identifier: id,
31 | username: username,
32 | introduce: introduce,
33 | profileImageURL: imageURL
34 | )
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/NicknameDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NicknameDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/25.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct NicknameDTO: Codable {
12 | let username: String
13 | }
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/PostDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostDTO.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/30/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct PostDTO: Decodable {
12 | let member: MemberDTO
13 | let board: BoardDTO
14 | let tag: [String]
15 | }
16 |
17 | extension PostDTO {
18 | func toDomain() -> Post {
19 | return Post(
20 | member: member.toDomain(),
21 | board: board.toDomain(),
22 | tag: tag
23 | )
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/PostsPageDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostsPageDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2024/02/04.
6 | // Copyright © 2024 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct PostsPageDTO: Decodable {
12 | let lastID: Int
13 | let posts: [PostDTO]
14 |
15 | enum CodingKeys: String, CodingKey {
16 | case lastID = "lastId"
17 | case posts = "boardsResDto"
18 | }
19 | }
20 |
21 | struct PostRequestDTO: Encodable {
22 | let cursor: Int?
23 | let memberId: String?
24 | }
25 |
26 | extension PostsPageDTO {
27 | func toDomain() -> PostsPage {
28 | return PostsPage(
29 | cursor: lastID,
30 | posts: posts.map { $0.toDomain() }
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/PresignedURLDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PresignedURLDTO.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/7/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct PresignedURLDTO: Decodable {
12 | let preSignedURL: String
13 |
14 | enum CodingKeys: String, CodingKey {
15 | case preSignedURL = "preSignedUrl"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/ProfileImageDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileImageDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/25.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct ProfileImageDTO: Decodable {
12 | let profileImage: URL
13 |
14 | enum CodingKeys: String, CodingKey {
15 | case profileImage = "profile-Image"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/ReportDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportDTO.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/5/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct ReportDTO: Codable {
12 | let memberID: Int?
13 | let boardID: Int
14 | let reportType: String
15 |
16 | enum CodingKeys: String, CodingKey {
17 | case memberID = "memberId"
18 | case boardID = "boardId"
19 | case reportType
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/Response.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Response.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/23/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct Response: Decodable {
12 | let statusCode: Int
13 | let message: String
14 | let data: Data?
15 | }
16 |
17 | struct EmptyData: Decodable { }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/UploadPostDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UploadPostDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/05.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UploadPostDTO: Decodable {
12 | let id: Int
13 | let title: String
14 | let content: String?
15 | let latitude, longitude: Double
16 | let tag: [String]
17 | }
18 |
19 | struct UploadPostRequestDTO: Encodable {
20 | let title: String
21 | let content: String?
22 | let latitude, longitude: Double
23 | let tag: [String]
24 | }
25 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/DTOs/UploadVideoDTO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UploadVideoDTO.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/05.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UploadVideoRequestDTO: Encodable {
12 | let boardID: Int
13 | let filetype: String
14 |
15 | enum CodingKeys: String, CodingKey {
16 | case boardID = "boardId"
17 | case filetype
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/EndPoint/EndPoint.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EndPoint.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/13.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol RequestResponsable: Requestable, Responsable { }
11 |
12 | final class EndPoint: RequestResponsable {
13 | typealias Response = R
14 |
15 | var baseURL: String
16 | var path: String
17 | var method: HTTPMethod
18 | var queryParameters: Encodable?
19 | var bodyParameters: Encodable?
20 | var headers: [String: String]?
21 |
22 | init(baseURL: String = Bundle.main.infoDictionary?["BASE_URL"] as? String ?? "",
23 | path: String,
24 | method: HTTPMethod,
25 | queryParameters: Encodable? = nil,
26 | bodyParameters: Encodable? = nil,
27 | headers: [String: String]? = ["Content-Type": "application/json"]) {
28 | self.baseURL = baseURL
29 | self.path = path
30 | self.method = method
31 | self.queryParameters = queryParameters
32 | self.bodyParameters = bodyParameters
33 | self.headers = headers
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/EndPoint/Factories/DefaultPostManagerEndPointFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostManagerEndPointFactory.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/5/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol PostManagerEndPointFactory {
12 | func reportPlaybackVideoEndpoint(boardID: Int, reportType: String) -> EndPoint>
13 | func deletePlaybackVideoEndpoint(boardID: Int) -> EndPoint>
14 | }
15 |
16 | struct DefaultPostManagerEndPointFactory: PostManagerEndPointFactory {
17 | func reportPlaybackVideoEndpoint(boardID: Int, reportType: String) -> EndPoint> {
18 | let bodyParmeters: ReportDTO = ReportDTO(
19 | memberID: nil,
20 | boardID: boardID,
21 | reportType: reportType)
22 |
23 | return EndPoint(
24 | path: "/report",
25 | method: .POST,
26 | bodyParameters: bodyParmeters)
27 | }
28 |
29 | func deletePlaybackVideoEndpoint(boardID: Int) -> EndPoint> {
30 | let queryParameters = ["boardId": boardID]
31 | return EndPoint(
32 | path: "/board",
33 | method: .DELETE,
34 | queryParameters: queryParameters
35 | )
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/EndPoint/Factories/SignUpEndPointFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpEndPointsFactory.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/27/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol SignUpEndPointFactory {
12 | func makeKakaoSignUpEndPoint(socialToken: String, username: String) -> EndPoint>
13 | func makeAppleSignUpEndPoint(identityToken: String, username: String) -> EndPoint>
14 | }
15 |
16 | final class DefaultSignUpEndPointFactory: SignUpEndPointFactory {
17 | func makeKakaoSignUpEndPoint(socialToken: String, username: String) -> EndPoint> {
18 | var bodyParameters = [String: String]()
19 | bodyParameters.updateValue(socialToken, forKey: "accessToken")
20 | bodyParameters.updateValue(username, forKey: "username")
21 |
22 | return EndPoint(
23 | path: "/oauth/signup/kakao",
24 | method: .POST,
25 | bodyParameters: bodyParameters
26 | )
27 | }
28 |
29 | func makeAppleSignUpEndPoint(identityToken: String, username: String) -> EndPoint> {
30 | var bodyParameters: [String: String] = [:]
31 | bodyParameters.updateValue(identityToken, forKey: "identityToken")
32 | bodyParameters.updateValue(username, forKey: "username")
33 |
34 | return EndPoint(
35 | path: "/oauth/signup/apple",
36 | method: .POST,
37 | bodyParameters: bodyParameters)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/EndPoint/HTTPMethod.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPMethod.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/13.
6 | //
7 |
8 | import Foundation
9 |
10 | enum HTTPMethod: String {
11 | case GET
12 | case POST
13 | case PUT
14 | case PATCH
15 | case DELETE
16 | }
17 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/EndPoint/Responsable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Responsable.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/13.
6 | //
7 |
8 | protocol Responsable {
9 | associatedtype Response
10 | }
11 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/CheckSignUp.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "isAlreadyExist": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/CheckUserName.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "isValid": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/DeleteUser.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "username": "hwani"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/DeleteVideo.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/GetMember.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "id": 221,
6 | "username": "hwani",
7 | "introduce": "Hi, my name is hwani",
8 | "profile_image_url": "https://qi-o.qoo10cdn.com/goods_image_big/3/3/1/6/8645113316_l.jpg"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/LoginData.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "accessToken": "mockAccessToken",
6 | "refreshToken": "mockRefreshToken"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/PatchIntroduce.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "introduce": "야자타임을 좋아하고 더운걸 싫어하는 화니라고해요"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/PatchProfileImage.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "profile-image": "https://i.ibb.co/qML8vdN/2023-11-25-9-08-01.png"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/PatchUserName.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "username": "hwani"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/PostListEnd.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": [
5 |
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockData/ReportPlaybackVideo.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "memberId": 221,
6 | "boardId": 5,
7 | "reportType": "청소년에게 유해한 내용이에요"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Network/Mock/MockURLProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockURLProtocol.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/24.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class MockURLProtocol: URLProtocol {
12 | static var requestHandler: ((URLRequest) -> (HTTPURLResponse?, Data?, Error?))?
13 |
14 | override class func canInit(with request: URLRequest) -> Bool {
15 | return true
16 | }
17 |
18 | override class func canonicalRequest(for request: URLRequest) -> URLRequest {
19 | return request
20 | }
21 |
22 | override func startLoading() {
23 | guard let handler = MockURLProtocol.requestHandler else { return }
24 | let (response, data, error) = handler(request)
25 |
26 | if let error = error {
27 | client?.urlProtocol(self, didFailWithError: error)
28 | }
29 |
30 | if let response = response {
31 | client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
32 | }
33 |
34 | if let data = data {
35 | client?.urlProtocol(self, didLoad: data)
36 | }
37 |
38 | client?.urlProtocolDidFinishLoading(self)
39 | }
40 |
41 | override func stopLoading() { }
42 | }
43 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LayoverIcon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/AppIcon.appiconset/LayoverIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/AppIcon.appiconset/LayoverIcon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x06",
9 | "green" : "0x06",
10 | "red" : "0x06"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Correct.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFF",
9 | "green" : "0x84",
10 | "red" : "0x0A"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/DarkGrey.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x13",
9 | "green" : "0x13",
10 | "red" : "0x13"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/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" : "0x41",
9 | "green" : "0x41",
10 | "red" : "0xFF"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Grey100.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xF6",
9 | "green" : "0xF6",
10 | "red" : "0xF6"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Grey200.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xE7",
9 | "green" : "0xE7",
10 | "red" : "0xE7"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Grey300.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xC4",
9 | "green" : "0xC4",
10 | "red" : "0xC4"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Grey400.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xA3",
9 | "green" : "0xA3",
10 | "red" : "0xA3"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Grey500.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x4B",
9 | "green" : "0x4B",
10 | "red" : "0x4B"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/Kakao.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.231",
9 | "green" : "0.922",
10 | "red" : "1.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/LayoverWhite.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 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Colors/PrimaryPurple.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xEE",
9 | "green" : "0x4F",
10 | "red" : "0x81"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "normalImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "normalImage 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "normalImage 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LONormalThumb.imageset/normalImage.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "selectedImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "selectedImage 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "selectedImage 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LOSelectedThumb.imageset/selectedImage.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LocationPin.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "LocationPin@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "LocationPin@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/LocationPin.imageset/LocationPin@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Setting.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "Setting@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "Setting@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Setting.imageset/Setting@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Title.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "Title@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "Title@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/Title.imageset/Title@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "appleLogo.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "appleLogo 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "appleLogo 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/appleLogo.imageset/appleLogo.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Close Button@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Close Button.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "Close Button@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "Close Button@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Document.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "Document@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "Document@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/content.imageset/Document@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "leading-icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "leading-icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "leading-icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/down.imageset/leading-icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_tab_back.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "icon_tab_back@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "icon_tab_back@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/icon_tab_back.imageset/icon_tab_back@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "kakaoLogo.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "kakaoLogo 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "kakaoLogo 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/kakaoLogo.imageset/kakaoLogo.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LayoverLogo.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "LayoverLogo 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "LayoverLogo 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/loLogo.imageset/LayoverLogo.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "map.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "map@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "map@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "template"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/map.imageset/map@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "map_pin_highlighted.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "map_pin_highlighted@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "map_pin_highlighted@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mapPin.imageset/map_pin_highlighted@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mute_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "mute_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "mute_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/mute.imageset/mute_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "location_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "location_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "location_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/myLocation.imageset/location_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pause.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "pause 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "pause 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/pause.imageset/pause.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "photo_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "photo_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "photo_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/photo.imageset/photo_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "planet.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "planet@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "planet@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "template"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/planet.imageset/planet@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "play.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "play 1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "play 2.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play 1.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play 2.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/play.imageset/play.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "plus_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "plus_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "plus_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/plus.imageset/plus_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "profile.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "profile@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "profile@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/profile.imageset/profile@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "interface-arrows-round-right--diagram-round-arrow-right.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "interface-arrows-round-right--diagram-round-arrow-right@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "interface-arrows-round-right--diagram-round-arrow-right@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/retry.imageset/interface-arrows-round-right--diagram-round-arrow-right@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "scissors_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "scissors_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "scissors_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/scissors.imageset/scissors_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "smallPlus.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "smallPlus@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "smallPlus@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/smallPlus.imageset/smallPlus@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/3@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "3.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "3@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "3@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "template"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "box.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "box@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "box@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/tag.imageset/box@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "volume_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "volume_icon@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "volume_icon@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | },
23 | "properties" : {
24 | "template-rendering-intent" : "original"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon@2x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Assets.xcassets/volume.imageset/volume_icon@3x.png
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Fonts/Dashboard-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Fonts/Dashboard-Regular.ttf
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Fonts/Pretendard-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Fonts/Pretendard-Bold.ttf
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Fonts/Pretendard-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Fonts/Pretendard-Regular.ttf
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Resources/Fonts/Pretendard-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Resources/Fonts/Pretendard-SemiBold.ttf
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Configurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Configurator.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/14/23.
6 | //
7 |
8 | import UIKit
9 |
10 | protocol Configurator {
11 | associatedtype ViewController: UIViewController
12 | func configure(_ viewController: ViewController)
13 | }
14 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditProfile/EditProfileConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditProfileConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/27.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class EditProfileConfigurator: Configurator {
12 |
13 | typealias ViewController = EditProfileViewController
14 |
15 | static let shared = EditProfileConfigurator()
16 |
17 | private init() { }
18 |
19 | func configure(_ viewController: ViewController) {
20 | let viewController = viewController
21 | let interactor = EditProfileInteractor()
22 | let presenter = EditProfilePresenter()
23 | let worker = UserWorker()
24 | let router = EditProfileRouter()
25 |
26 | router.viewController = viewController
27 | router.dataStore = interactor
28 | viewController.interactor = interactor
29 | viewController.router = router
30 | interactor.presenter = presenter
31 | interactor.userWorker = worker
32 | presenter.viewController = viewController
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditProfile/EditProfileRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditProfileRouter.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/27.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EditProfileRoutingLogic {
12 |
13 | }
14 |
15 | protocol EditProfileDataPassing {
16 | var dataStore: EditProfileDataStore? { get }
17 | }
18 |
19 | final class EditProfileRouter: EditProfileRoutingLogic, EditProfileDataPassing {
20 |
21 | // MARK: - Properties
22 |
23 | weak var viewController: EditProfileViewController?
24 | var dataStore: EditProfileDataStore?
25 |
26 | // MARK: - Routing
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditTag/EditTagConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditTagConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/03.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class EditTagConfigurator: Configurator {
12 |
13 | typealias ViewController = EditTagViewController
14 |
15 | static let shared = EditTagConfigurator()
16 |
17 | private init() { }
18 |
19 | func configure(_ viewController: ViewController) {
20 | let viewController = viewController
21 | let interactor = EditTagInteractor()
22 | let presenter = EditTagPresenter()
23 | let router = EditTagRouter()
24 |
25 | router.viewController = viewController
26 | router.dataStore = interactor
27 | viewController.interactor = interactor
28 | viewController.router = router
29 | interactor.presenter = presenter
30 | presenter.viewController = viewController
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditTag/EditTagModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditTagModels.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/03.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum EditTagModels {
12 |
13 | static let maxTagCount: Int = 3
14 | static let maxTagLength: Int = 5
15 |
16 | enum FetchTags {
17 | struct Request {
18 |
19 | }
20 | struct Response {
21 | let tags: [String]
22 | }
23 | struct ViewModel {
24 | let tags: [String]
25 | var tagCountDescription: String
26 | }
27 | }
28 |
29 | enum AddTag {
30 | struct Request {
31 | let tags: [String]
32 | let newTag: String
33 | }
34 | struct Response {
35 | let tags: [String]
36 | let addedTag: String?
37 | }
38 | struct ViewModel {
39 | let addedTag: String?
40 | let tagCountDescription: String
41 | }
42 | }
43 |
44 | enum EditTags {
45 | struct Request {
46 | let editedTags: [String]
47 | }
48 | struct Response {
49 | let editedTags: [String]
50 | }
51 | struct ViewModel {
52 | let tagCountDescription: String
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditVideo/EditVideoConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditVideoConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/29.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class EditVideoConfigurator: Configurator {
12 |
13 | typealias ViewController = EditVideoViewController
14 |
15 | static let shared = EditVideoConfigurator()
16 |
17 | private init() { }
18 |
19 | func configure(_ viewController: ViewController) {
20 | let viewController = viewController
21 | let videoFileWorker = VideoFileWorker()
22 | let interactor = EditVideoInteractor()
23 | let presenter = EditVideoPresenter()
24 | let router = EditVideoRouter()
25 |
26 | router.viewController = viewController
27 | router.dataStore = interactor
28 | viewController.interactor = interactor
29 | viewController.router = router
30 | interactor.presenter = presenter
31 | interactor.videoFileWorker = videoFileWorker
32 | presenter.viewController = viewController
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditVideo/EditVideoModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditVideoModels.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/29.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum EditVideoModels {
12 |
13 | enum FetchVideo {
14 | struct Request {
15 | var editedVideoURL: URL?
16 | var videoRange: ClosedRange = 3.0...60.0
17 | }
18 | struct Response {
19 | let isEdited: Bool
20 | let videoURL: URL
21 | let duration: Double
22 | var isWithinRange: Bool
23 | }
24 | struct ViewModel {
25 | let isEdited: Bool
26 | let videoURL: URL
27 | let duration: Double
28 | let canNext: Bool
29 | }
30 | }
31 |
32 | enum DidFinishViedoEditing {
33 | struct Request {
34 | let isMuted: Bool
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditVideo/EditVideoPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditVideoPresenter.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/29.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EditVideoPresentationLogic {
12 | func presentVideo(with response: EditVideoModels.FetchVideo.Response)
13 | }
14 |
15 | final class EditVideoPresenter: EditVideoPresentationLogic {
16 |
17 | // MARK: - Properties
18 |
19 | typealias Models = EditVideoModels
20 | weak var viewController: EditVideoDisplayLogic?
21 |
22 | func presentVideo(with response: EditVideoModels.FetchVideo.Response) {
23 | let viewModel = Models.FetchVideo.ViewModel(isEdited: response.isEdited,
24 | videoURL: response.videoURL,
25 | duration: response.duration,
26 | canNext: response.isWithinRange)
27 | viewController?.displayVideo(viewModel: viewModel)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditVideo/EditVideoRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditVideoRouter.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/29.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol EditVideoRoutingLogic {
12 | func routeToNext()
13 | }
14 |
15 | protocol EditVideoDataPassing {
16 | var dataStore: EditVideoDataStore? { get }
17 | }
18 |
19 | final class EditVideoRouter: NSObject, EditVideoRoutingLogic, EditVideoDataPassing {
20 |
21 | // MARK: - Properties
22 |
23 | weak var viewController: EditVideoViewController?
24 | var dataStore: EditVideoDataStore?
25 |
26 | // MARK: - Routing
27 |
28 | func routeToNext() {
29 | let nextViewController = UploadPostViewController()
30 | guard let source = dataStore,
31 | var destination = nextViewController.router?.dataStore
32 | else { return }
33 |
34 | // Data Passing
35 | destination.videoURL = source.videoURL
36 | destination.isMuted = source.isMuted
37 | nextViewController.hidesBottomBarWhenPushed = true
38 | viewController?.navigationController?.pushViewController(nextViewController, animated: true)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/EditVideo/EditVideoWorker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditVideoWorker.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/29.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class EditVideoWorker {
12 |
13 | // MARK: - Properties
14 |
15 | typealias Models = EditVideoModels
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Home/HomeConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/16/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class HomeConfigurator: Configurator {
12 |
13 | static let shared = HomeConfigurator()
14 |
15 | private init() { }
16 |
17 | func configure(_ viewController: HomeViewController) {
18 | let router = HomeRouter()
19 | let presenter = HomePresenter()
20 | let interactor = HomeInteractor()
21 | let homeWorker = HomeWorker()
22 | let videoFileWorker = VideoFileWorker()
23 | let locationManager = CurrentLocationManager()
24 |
25 | router.viewController = viewController
26 | router.dataStore = interactor
27 | presenter.viewController = viewController
28 | interactor.presenter = presenter
29 | interactor.homeWorker = homeWorker
30 | interactor.videoFileWorker = videoFileWorker
31 | interactor.locationManager = locationManager
32 | viewController.router = router
33 | viewController.interactor = interactor
34 |
35 | router.dataStore = interactor
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Login/LoginConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 11/20/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class LoginConfigurator: Configurator {
12 | typealias ViewController = LoginViewController
13 |
14 | static let shared = LoginConfigurator()
15 |
16 | private init() { }
17 |
18 | func configure(_ viewController: LoginViewController) {
19 | let viewController = viewController
20 | let interactor = LoginInteractor()
21 | let presenter = LoginPresenter()
22 | // TODO: 실행 전 Worker Mock인지 확인
23 | let worker = LoginWorker()
24 | let router = LoginRouter()
25 |
26 | router.viewController = viewController
27 | router.dataStore = interactor
28 | viewController.interactor = interactor
29 | viewController.router = router
30 | interactor.presenter = presenter
31 | interactor.worker = worker
32 | presenter.viewController = viewController
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Login/LoginModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginModels.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/14/23.
6 | //
7 |
8 | import Foundation
9 |
10 | enum LoginModels {
11 |
12 | // MARK: - Use Cases
13 |
14 | enum PerformKakaoLogin {
15 | struct Request {
16 | }
17 |
18 | struct Response {
19 |
20 | }
21 |
22 | struct ViewModel {
23 |
24 | }
25 | }
26 |
27 | enum PerformAppleLogin {
28 | struct Request {
29 | let loginViewController: LoginViewController
30 | }
31 |
32 | struct Response {
33 |
34 | }
35 |
36 | struct ViewModel {
37 |
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Login/LoginPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginPresenter.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/14/23.
6 | //
7 |
8 | import UIKit
9 |
10 | protocol LoginPresentationLogic {
11 | func presentPerformLogin()
12 | func presentSignUp(with response: LoginModels.PerformKakaoLogin.Response)
13 | func presentSignUp(with response: LoginModels.PerformAppleLogin.Response)
14 | }
15 |
16 | final class LoginPresenter {
17 |
18 | // MARK: - Properties
19 |
20 | typealias Models = LoginModels
21 | weak var viewController: LoginDisplayLogic?
22 |
23 | }
24 |
25 | // MARK: - Use Case - Login
26 |
27 | extension LoginPresenter: LoginPresentationLogic {
28 | func presentPerformLogin() {
29 | viewController?.navigateToMain()
30 | }
31 |
32 | func presentSignUp(with response: LoginModels.PerformKakaoLogin.Response) {
33 | viewController?.routeToSignUp(with: LoginModels.PerformKakaoLogin.ViewModel())
34 | }
35 |
36 | func presentSignUp(with response: LoginModels.PerformAppleLogin.Response) {
37 | viewController?.routeToSignUp(with: LoginModels.PerformAppleLogin.ViewModel())
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Map/LOAnnotation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LOAnnotation.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/26.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import MapKit
10 |
11 | final class LOAnnotation: NSObject, MKAnnotation {
12 |
13 | @objc dynamic var coordinate: CLLocationCoordinate2D
14 | let boardID: Int
15 | let thumbnailImageURL: URL?
16 |
17 | init(coordinate: CLLocationCoordinate2D,
18 | boardID: Int,
19 | thumbnailImageURL: URL?) {
20 | self.coordinate = coordinate
21 | self.boardID = boardID
22 | self.thumbnailImageURL = thumbnailImageURL
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Map/MapConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/15.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class MapConfigurator: Configurator {
12 | typealias ViewController = MapViewController
13 |
14 | static let shared = MapConfigurator()
15 |
16 | private init() { }
17 |
18 | func configure(_ viewController: ViewController) {
19 | let viewController = viewController
20 | let interactor = MapInteractor()
21 | let presenter = MapPresenter()
22 | let router = MapRouter()
23 | let worker = MapWorker()
24 | let videoFileWorker = VideoFileWorker()
25 | let locationManager = CurrentLocationManager()
26 |
27 | router.viewController = viewController
28 | viewController.interactor = interactor
29 | interactor.presenter = presenter
30 | interactor.worker = worker
31 | interactor.videoFileWorker = videoFileWorker
32 | interactor.locationManager = locationManager
33 | presenter.viewController = viewController
34 | viewController.router = router
35 | router.dataStore = interactor
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Playback/PlaybackConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlaybackConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 11/28/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class PlaybackConfigurator: Configurator {
12 | typealias ViewController = PlaybackViewController
13 |
14 | static let shared = PlaybackConfigurator()
15 |
16 | private init() { }
17 |
18 | func configure(_ viewController: PlaybackViewController) {
19 | let viewController: PlaybackViewController = viewController
20 | let interactor: PlaybackInteractor = PlaybackInteractor()
21 | let presenter: PlaybackPresenter = PlaybackPresenter()
22 | let worker: PlaybackWorkerProtocol = PlaybackWorker()
23 | let router: PlaybackRouter = PlaybackRouter()
24 |
25 | router.viewController = viewController
26 | router.dataStore = interactor
27 | viewController.interactor = interactor
28 | viewController.router = router
29 | interactor.presenter = presenter
30 | interactor.worker = worker
31 | presenter.viewController = viewController
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Profile/ProfileConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/21.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class ProfileConfigurator: Configurator {
12 |
13 | typealias ViewController = ProfileViewController
14 |
15 | static let shared = ProfileConfigurator()
16 |
17 | private init() { }
18 |
19 | func configure(_ viewController: ViewController) {
20 | let viewController = viewController
21 | let interactor = ProfileInteractor()
22 | let worker = UserWorker()
23 | let presenter = ProfilePresenter()
24 | let router = ProfileRouter()
25 |
26 | router.viewController = viewController
27 | router.dataStore = interactor
28 | viewController.interactor = interactor
29 | viewController.router = router
30 | interactor.presenter = presenter
31 | interactor.userWorker = worker
32 | presenter.viewController = viewController
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Profile/ProfileModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProfileModels.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/21.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum ProfileModels {
12 |
13 | struct Profile: Hashable {
14 | let username: String
15 | let introduce: String?
16 | let profileImageURL: URL?
17 | }
18 |
19 | struct DisplayedPost: Hashable {
20 | let id: Int
21 | let thumbnailImageData: URL?
22 | let status: BoardStatus
23 | }
24 |
25 | enum FetchProfile {
26 |
27 | struct Request {
28 | }
29 |
30 | struct Response {
31 | let userProfile: Profile
32 | let displayedPosts: [DisplayedPost]
33 | }
34 |
35 | struct ViewModel {
36 | let userProfile: Profile
37 | let displayedPosts: [DisplayedPost]
38 | }
39 | }
40 |
41 | enum FetchMorePosts {
42 | struct Request {
43 | }
44 |
45 | struct Response {
46 | let displayedPosts: [DisplayedPost]
47 | }
48 |
49 | struct ViewModel {
50 | let displayedPosts: [DisplayedPost]
51 | }
52 | }
53 |
54 | enum ShowPostDetail {
55 | struct Request {
56 | let startIndex: Int
57 | }
58 |
59 | struct Response {
60 | }
61 |
62 | struct ViewModel {
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Report/ReportConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/4/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class ReportConfigurator: Configurator {
12 | static let shared = ReportConfigurator()
13 |
14 | private init() { }
15 |
16 | func configure(_ viewController: ReportViewController) {
17 | let viewController: ReportViewController = viewController
18 | let interactor: ReportInteractor = ReportInteractor()
19 | let presenter: ReportPresenter = ReportPresenter()
20 | let worker: ReportWorker = ReportWorker()
21 | // let worker: ReportWorkerProtocol = MockReportWorker()
22 | let router: ReportRouter = ReportRouter()
23 |
24 | router.viewController = viewController
25 | router.dataStore = interactor
26 | viewController.interactor = interactor
27 | viewController.router = router
28 | interactor.presenter = presenter
29 | interactor.worker = worker
30 | presenter.viewController = viewController
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Report/ReportInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportInteractor.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/4/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ReportBusinessLogic {
12 | @discardableResult
13 | func reportPlaybackVideo(with request: ReportModels.ReportPlaybackVideo.Request) -> Task
14 | }
15 |
16 | protocol ReportDataStore {
17 | var boardID: Int? { get set }
18 | }
19 |
20 | final class ReportInteractor: ReportBusinessLogic, ReportDataStore {
21 |
22 | // MARK: - Properties
23 |
24 | typealias Models = ReportModels
25 |
26 | var worker: ReportWorkerProtocol?
27 | var presenter: ReportPresentationLogic?
28 |
29 | var boardID: Int?
30 |
31 | func reportPlaybackVideo(with request: ReportModels.ReportPlaybackVideo.Request) -> Task {
32 | Task {
33 | guard let boardID,
34 | let worker
35 | else { return false }
36 | let result: Bool = await worker.reportPlaybackVideo(boardID: boardID, reportContent: request.reportContent)
37 | let response: Models.ReportPlaybackVideo.Response = Models.ReportPlaybackVideo.Response(reportResult: result)
38 | await MainActor.run {
39 | presenter?.presentReportPlaybackVideo(with: response)
40 | }
41 | return result
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Report/ReportModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportModels.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/4/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum ReportModels {
12 |
13 | // MARK: - Use Cases
14 |
15 | enum ReportPlaybackVideo {
16 | enum ReportMessage {
17 | case success
18 | case fail
19 |
20 | var description: String {
21 | switch self {
22 | case .success:
23 | "신고가 접수되었습니다.\n해당 컨텐츠는 검토 후, 24시간 내에 차단 처리됩니다."
24 | case .fail:
25 | "신고 접수에 실패했습니다. 다시 시도해주세요."
26 | }
27 | }
28 | }
29 | struct Request {
30 | let reportContent: String
31 | }
32 |
33 | struct Response {
34 | let reportResult: Bool
35 | }
36 |
37 | struct ViewModel {
38 | let reportMessage: ReportMessage
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Report/ReportPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportPresenter.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/4/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ReportPresentationLogic {
12 | func presentReportPlaybackVideo(with response: ReportModels.ReportPlaybackVideo.Response)
13 | }
14 |
15 | final class ReportPresenter: ReportPresentationLogic {
16 |
17 | // MARK: - Properties
18 |
19 | typealias Models = ReportModels
20 | weak var viewController: ReportDisplayLogic?
21 |
22 | func presentReportPlaybackVideo(with response: ReportModels.ReportPlaybackVideo.Response) {
23 | let viewModel: Models.ReportPlaybackVideo.ViewModel
24 | viewModel = Models.ReportPlaybackVideo.ViewModel(reportMessage: response.reportResult ? .success : .fail)
25 | viewController?.displayReportResult(viewModel: viewModel)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Report/ReportRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportRouter.swift
3 | // Layover
4 | //
5 | // Created by 황지웅 on 12/4/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol ReportRoutingLogic {
12 | func routeToNext()
13 | }
14 |
15 | protocol ReportDataPassing {
16 | var dataStore: ReportDataStore? { get }
17 | }
18 |
19 | final class ReportRouter: NSObject, ReportRoutingLogic, ReportDataPassing {
20 |
21 | // MARK: - Properties
22 |
23 | weak var viewController: ReportViewController?
24 | var dataStore: ReportDataStore?
25 |
26 | // MARK: - Routing
27 |
28 | func routeToNext() {
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Setting/SettingConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/6/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class SettingConfigurator: Configurator {
12 |
13 | // MARK: - Properties
14 |
15 | static let shared = SettingConfigurator()
16 |
17 | // MARK: - Intializer
18 |
19 | private init() { }
20 |
21 | // MARK: - Methods
22 |
23 | func configure(_ viewController: SettingViewController) {
24 | let interactor = SettingInteractor()
25 | let presenter = SettingPresenter()
26 | let router = SettingRouter()
27 | let settingWorker = SettingWorker()
28 | let userWorker = UserWorker()
29 |
30 | viewController.router = router
31 | viewController.interactor = interactor
32 | interactor.settingWorker = settingWorker
33 | interactor.userWorker = userWorker
34 | interactor.presenter = presenter
35 | presenter.viewController = viewController
36 | router.viewController = viewController
37 | router.dataStore = interactor
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Setting/SettingRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingRouter.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/6/23.
6 | // Copyright (c) 2023 CodeBomber. All rights reserved.
7 | //
8 | // This file was generated by the Clean Swift Xcode Templates so
9 | // you can apply clean architecture to your iOS and Mac projects,
10 | // see http://clean-swift.com
11 | //
12 |
13 | import UIKit
14 | import SafariServices
15 |
16 | protocol SettingRoutingLogic {
17 | func showSafariViewController(url: URL)
18 | func routeToLogin()
19 | }
20 |
21 | protocol SettingDataPassing {
22 | var dataStore: SettingDataStore? { get }
23 | }
24 |
25 | final class SettingRouter: SettingRoutingLogic, SettingDataPassing {
26 |
27 | // MARK: - Properties
28 |
29 | weak var viewController: SettingViewController?
30 | var dataStore: SettingDataStore?
31 |
32 | // MARK: - Methods
33 |
34 | func showSafariViewController(url: URL) {
35 | let safariViewController = SFSafariViewController(url: url)
36 | viewController?.present(safariViewController, animated: true, completion: nil)
37 | }
38 |
39 | func routeToLogin() {
40 | let loginViewController = LoginViewController()
41 | guard let rootNavigationController = viewController?.view.window?.rootViewController
42 | as? UINavigationController else { return }
43 | rootNavigationController.setNavigationBarHidden(false, animated: true)
44 | rootNavigationController.setViewControllers([loginViewController], animated: true)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Setting/SettingWorker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingWorker.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/6/23.
6 | // Copyright (c) 2023 CodeBomber. All rights reserved.
7 | //
8 | // This file was generated by the Clean Swift Xcode Templates so
9 | // you can apply clean architecture to your iOS and Mac projects,
10 | // see http://clean-swift.com
11 | //
12 |
13 | import Foundation
14 |
15 | protocol SettingWorkerProtocol {
16 | func versionNumber() -> String?
17 | }
18 |
19 | final class SettingWorker: SettingWorkerProtocol {
20 |
21 | // MARK: - Methods
22 |
23 | func versionNumber() -> String? {
24 | System.versionNumber()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/SignUpScene/SignUpConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/15.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class SignUpConfigurator: Configurator {
12 | static let shared = SignUpConfigurator()
13 |
14 | private init() { }
15 |
16 | func configure(_ viewController: SignUpViewController) {
17 | let viewController = viewController
18 | let interactor = SignUpInteractor()
19 | let userWorker = UserWorker()
20 | let signUpWorker = SignUpWorker()
21 | let presenter = SignUpPresenter()
22 | let router = SignUpRouter()
23 | viewController.interactor = interactor
24 | viewController.router = router
25 | interactor.presenter = presenter
26 | interactor.userWorker = userWorker
27 | interactor.signUpWorker = signUpWorker
28 | presenter.viewController = viewController
29 | router.viewController = viewController
30 | router.dataStore = interactor
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/SignUpScene/SignUpModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpModels.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/15.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum SignUpModels {
12 |
13 | // MARK: - Validate Nickname Use Case
14 |
15 | enum ValidateNickname {
16 | struct Request {
17 | var nickname: String
18 | }
19 | struct Response {
20 | var nicknameState: NicknameState
21 | }
22 | struct ViewModel {
23 | var canCheckDuplication: Bool
24 | var alertDescription: String?
25 | }
26 | }
27 |
28 | // MARK: - Check Nickname Duplication Use Case
29 | enum CheckDuplication {
30 | struct Request {
31 | var nickname: String
32 | }
33 | struct Response {
34 | var isValid: Bool
35 | }
36 | struct ViewModel {
37 | var canSignUp: Bool
38 | var alertDescription: String {
39 | canSignUp ? "사용 가능한 닉네임입니다." : "사용 중인 닉네임입니다."
40 | }
41 | }
42 | }
43 |
44 | // MARK: - Sign Up Use Case
45 |
46 | enum SignUp {
47 | enum LoginType {
48 | case kakao
49 | case apple
50 | }
51 |
52 | struct Request {
53 | var nickname: String
54 | }
55 |
56 | struct Response {
57 | var isSuccess: Bool
58 | }
59 |
60 | struct ViewModel {
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/SignUpScene/SignUpPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpPresenter.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/11/15.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol SignUpPresentationLogic {
12 | func presentNicknameValidation(with response: SignUpModels.ValidateNickname.Response)
13 | func presentNicknameDuplication(with response: SignUpModels.CheckDuplication.Response)
14 | func presentSignUpSuccess()
15 | }
16 |
17 | final class SignUpPresenter: SignUpPresentationLogic {
18 |
19 | // MARK: - Properties
20 |
21 | typealias Models = SignUpModels
22 | weak var viewController: SignUpDisplayLogic?
23 |
24 | // MARK: - UseCase: 닉네임 유효성 검사
25 |
26 | func presentNicknameValidation(with response: Models.ValidateNickname.Response) {
27 | let viewModel = Models.ValidateNickname.ViewModel(canCheckDuplication: response.nicknameState == .valid,
28 | alertDescription: response.nicknameState.description)
29 | viewController?.displayNicknameValidation(response: viewModel)
30 | }
31 |
32 | func presentNicknameDuplication(with response: SignUpModels.CheckDuplication.Response) {
33 | let viewModel = Models.CheckDuplication.ViewModel(canSignUp: response.isValid)
34 | viewController?.displayNicknameDuplication(response: viewModel)
35 | }
36 |
37 | func presentSignUpSuccess() {
38 | viewController?.navigateToMain()
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/SignUpScene/SignUpRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpRouter.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/26/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol SignUpRoutingLogic {
12 | func routeToBack()
13 | func navigateToMain()
14 | }
15 |
16 | protocol SignUpDataPassing {
17 | var dataStore: SignUpDataStore? { get set }
18 | }
19 |
20 | final class SignUpRouter: SignUpRoutingLogic, SignUpDataPassing {
21 |
22 | // MARK: - Properties
23 |
24 | typealias Models = SignUpModels
25 | weak var viewController: SignUpViewController?
26 | var dataStore: SignUpDataStore?
27 |
28 | // MARK: - Routing
29 |
30 | func routeToBack() {
31 | viewController?.navigationController?.popViewController(animated: true)
32 | }
33 |
34 | func navigateToMain() {
35 | let mainTabBarViewController = MainTabBarViewController()
36 | viewController?.navigationController?.setNavigationBarHidden(true, animated: false)
37 | viewController?.navigationController?.setViewControllers([mainTabBarViewController], animated: true)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/Tabbar/MainTabBarViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainTabBarViewController.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/14/23.
6 | //
7 |
8 | import UIKit
9 |
10 | final class MainTabBarViewController: UITabBarController {
11 |
12 | // MARK: - Object lifecycle
13 |
14 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
15 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
16 | setup()
17 | }
18 |
19 | required init?(coder aDecoder: NSCoder) {
20 | super.init(coder: aDecoder)
21 | setup()
22 | }
23 |
24 | // MARK: - Setup
25 |
26 | private func setup() {
27 | MainTabBarConfigurator.shared.configure(self)
28 | }
29 |
30 | // MARK: ViewController Life Cycle
31 |
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 | setUI()
35 | }
36 |
37 | // MARK: - UI
38 |
39 | private func setUI() {
40 | tabBar.tintColor = .primaryPurple
41 | tabBar.backgroundColor = .black
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TagPlayListConfigurator.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/29/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class TagPlayListConfigurator: Configurator {
12 |
13 | static let shared = TagPlayListConfigurator()
14 |
15 | private init() { }
16 |
17 | func configure(_ viewController: TagPlayListViewController) {
18 | let viewController = viewController
19 | let interactor = TagPlayListInteractor()
20 | let presenter = TagPlayListPresenter()
21 | let worker = TagPlayListWorker()
22 | let router = TagPlayListRouter()
23 |
24 | router.viewController = viewController
25 | router.dataStore = interactor
26 | viewController.interactor = interactor
27 | viewController.router = router
28 | interactor.presenter = presenter
29 | interactor.worker = worker
30 | presenter.viewController = viewController
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TagPlayListModels.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/29/23.
6 | // Copyright (c) 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum TagPlayListModels {
12 | // MARK: Use cases
13 |
14 | struct DisplayedPost: Hashable {
15 | let identifier: Int
16 | let thumbnailImageData: Data?
17 | let title: String
18 | }
19 |
20 | enum FetchPosts {
21 | struct Request {
22 | }
23 |
24 | struct Response {
25 | let post: [DisplayedPost]
26 | }
27 |
28 | struct ViewModel {
29 | let displayedPost: [DisplayedPost]
30 | }
31 | }
32 |
33 | enum FetchMorePosts {
34 | struct Request {
35 | }
36 |
37 | struct Response {
38 | let post: [DisplayedPost]
39 | }
40 |
41 | struct ViewModel {
42 | let displayedPost: [DisplayedPost]
43 | }
44 | }
45 |
46 | enum FetchTitleTag {
47 | struct Request {
48 | }
49 |
50 | struct Response {
51 | let titleTag: String
52 | }
53 |
54 | struct ViewModel {
55 | let title: String
56 | }
57 | }
58 |
59 | enum ShowPostsDetail {
60 | struct Request {
61 | let startIndex: Int
62 | }
63 |
64 | struct Response {
65 | }
66 |
67 | struct ViewModel {
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TagPlayListRouter.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/29/23.
6 | // Copyright (c) 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol TagPlayListRoutingLogic {
12 | func routeToPlayback()
13 | }
14 |
15 | protocol TagPlayListDataPassing {
16 | var dataStore: TagPlayListDataStore? { get }
17 | }
18 |
19 | final class TagPlayListRouter: TagPlayListRoutingLogic, TagPlayListDataPassing {
20 |
21 | // MARK: - Properties
22 |
23 | weak var viewController: TagPlayListViewController?
24 | var dataStore: TagPlayListDataStore?
25 |
26 | func routeToPlayback() {
27 | let playbackViewController: PlaybackViewController = PlaybackViewController()
28 | guard let source = dataStore,
29 | var destination = playbackViewController.router?.dataStore else { return }
30 |
31 | passDataToPlayback(source: source, destination: &destination)
32 | viewController?.navigationController?.pushViewController(playbackViewController, animated: true)
33 | }
34 |
35 | private func passDataToPlayback(source: TagPlayListDataStore, destination: inout PlaybackDataStore) {
36 | destination.parentView = .tag
37 | destination.index = source.postPlayStartIndex
38 | destination.posts = source.posts
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/UploadPost/UploadPostConfigurator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UploadPostConfigurator.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/03.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class UploadPostConfigurator: Configurator {
12 |
13 | typealias ViewController = UploadPostViewController
14 |
15 | static let shared = UploadPostConfigurator()
16 |
17 | private init() { }
18 |
19 | func configure(_ viewController: ViewController) {
20 | let viewController = viewController
21 | let interactor = UploadPostInteractor(locationManager: CurrentLocationManager())
22 | let presenter = UploadPostPresenter()
23 | let router = UploadPostRouter()
24 | let worker = UploadPostWorker()
25 |
26 | router.viewController = viewController
27 | router.dataStore = interactor
28 | viewController.interactor = interactor
29 | viewController.router = router
30 | interactor.presenter = presenter
31 | interactor.worker = worker
32 | presenter.viewController = viewController
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Scenes/UploadPost/UploadPostRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UploadPostRouter.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/01.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol UploadPostRoutingLogic {
12 | func routeToNext()
13 | func routeToBack()
14 | }
15 |
16 | protocol UploadPostDataPassing {
17 | var dataStore: UploadPostDataStore? { get }
18 | }
19 |
20 | final class UploadPostRouter: NSObject, UploadPostRoutingLogic, UploadPostDataPassing {
21 |
22 | // MARK: - Properties
23 |
24 | weak var viewController: UploadPostViewController?
25 | var dataStore: UploadPostDataStore?
26 |
27 | // MARK: - Routing
28 |
29 | func routeToNext() {
30 | let nextViewController = EditTagViewController()
31 | guard let source = dataStore,
32 | var destination = nextViewController.router?.dataStore
33 | else { return }
34 |
35 | destination.tags = source.tags
36 | nextViewController.modalPresentationStyle = .fullScreen
37 | viewController?.present(nextViewController, animated: true)
38 | }
39 |
40 | func routeToBack() {
41 | viewController?.navigationController?.popToRootViewController(animated: true)
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Services/Location/LocationFetcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocationFetcher.swift
3 | // Layover
4 | //
5 | // Created by kong on 2023/12/12.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import CoreLocation
10 |
11 | protocol LocationFetcherDelegate: AnyObject {
12 | func locationFetcher(_ fetcher: LocationFetcher, didUpdateLocations locations: [CLLocation])
13 | }
14 |
15 | protocol LocationFetcher {
16 | var location: CLLocation? { get }
17 | var locationFetcherDelegate: LocationFetcherDelegate? { get set }
18 | var authorizationStatus: CLAuthorizationStatus { get }
19 | var desiredAccuracy: CLLocationAccuracy { get set }
20 |
21 | func requestLocation()
22 | func startUpdatingLocation()
23 | func requestWhenInUseAuthorization()
24 | }
25 |
26 | extension CLLocationManager: LocationFetcher {
27 | var locationFetcherDelegate: LocationFetcherDelegate? {
28 | get {
29 | return delegate as? LocationFetcherDelegate
30 | }
31 | set {
32 | delegate = newValue as? CLLocationManagerDelegate
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Services/System.swift:
--------------------------------------------------------------------------------
1 | //
2 | // System.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/1/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum System {
12 |
13 | @UserDefaultStored(key: UserDefaultKey.hasBeenLaunchedBefore, defaultValue: false) static var hasBeenLaunchedBefore: Bool?
14 |
15 | static func isFirstLaunch() -> Bool {
16 | if hasBeenLaunchedBefore == false {
17 | hasBeenLaunchedBefore = true
18 | return true
19 | }
20 | return false
21 | }
22 |
23 | static func versionNumber() -> String? {
24 | guard let info = Bundle.main.infoDictionary,
25 | let currentVersion = info["CFBundleShortVersionString"] as? String else { return nil }
26 | return currentVersion
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Services/UserDefaults/UserDefaultStored.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserDefaultStored.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 11/26/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @propertyWrapper
12 | struct UserDefaultStored {
13 | private let key: String
14 | private let defaultValue: T?
15 |
16 | init(key: String, defaultValue: T?) {
17 | self.key = key
18 | self.defaultValue = defaultValue
19 | }
20 |
21 | var wrappedValue: T? {
22 | get {
23 | if let savedData = UserDefaults.standard.object(forKey: key) as? Data {
24 | let decoder = JSONDecoder()
25 | if let loadedObject = try? decoder.decode(T.self, from: savedData) {
26 | return loadedObject
27 | }
28 | }
29 | return defaultValue
30 | }
31 | set {
32 | let encoder = JSONEncoder()
33 | if let encodedObject = try? encoder.encode(newValue) {
34 | UserDefaults.standard.set(encodedObject, forKey: key)
35 | }
36 | }
37 | }
38 | }
39 |
40 | enum UserDefaultKey {
41 | static let isLoggedIn = "isLoggedIn"
42 | static let hasBeenLaunchedBefore = "hasBeenLaunchedBefore"
43 | static let memberId = "memberId"
44 | static let loginType = "loginType"
45 | }
46 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Workers/Mocks/StubAuthManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubAuthManager.swift
3 | // Layover
4 | //
5 | // Created by 김인환 on 12/2/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class StubAuthManager: AuthManagerProtocol {
12 |
13 | // MARK: Properties
14 |
15 | var accessToken: String? = "Fake Access Token"
16 | var refreshToken: String? = "Fake Refresh Token"
17 | var isLoggedIn: Bool? = true
18 | var loginType: LoginType? = .kakao
19 | var memberID: Int? = -1
20 | }
21 |
--------------------------------------------------------------------------------
/iOS/Layover/Layover/Workers/Mocks/sample.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/Layover/Workers/Mocks/sample.jpeg
--------------------------------------------------------------------------------
/iOS/Layover/Layover/en.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/LocationFetcher/MockLocationFetcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockLocationFetcher.swift
3 | // LayoverTests
4 | //
5 | // Created by kong on 2023/12/13.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 |
9 | import CoreLocation
10 |
11 | @testable import Layover
12 |
13 | final class MockLocationFetcher: LocationFetcher {
14 |
15 | var location: CLLocation?
16 | var locationFetcherDelegate: Layover.LocationFetcherDelegate?
17 | var desiredAccuracy: CLLocationAccuracy = kCLLocationAccuracyBest
18 | var authorizationStatus: CLAuthorizationStatus = .authorizedWhenInUse
19 |
20 | func requestLocation() { }
21 |
22 | func startUpdatingLocation() {
23 | location = CLLocation(latitude: 37.498206, longitude: 127.02761)
24 | guard let location else { return }
25 | locationFetcherDelegate?.locationFetcher(self, didUpdateLocations: [location])
26 | }
27 |
28 | func requestWhenInUseAuthorization() { }
29 |
30 | func requestAlwaysAuthorization() { }
31 | }
32 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/CheckSignUp.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "isAlreadyExist": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/CheckUserName.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "isValid": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/DeleteUser.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "username": "hwani"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/DeleteVideo.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/GetMember.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "id": 221,
6 | "username": "안유진",
7 | "introduce": "안녕하세요, 아이브의 안유진입니다.",
8 | "profile_image_url": "https://cdn.footballist.co.kr/news/photo/202307/170226_100422_1733.jpg"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/LoginData.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "accessToken": "mockAccessToken",
6 | "refreshToken": "mockRefreshToken"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PatchIntroduce.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "introduce": "야자타임을 좋아하고 더운걸 싫어하는 화니라고해요"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PatchProfileImage.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "profile-image": "https://i.ibb.co/qML8vdN/2023-11-25-9-08-01.png"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PatchUserName.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": {
5 | "username": "hwani"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PostBoard.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "id": 1,
6 | "title": "제목",
7 | "content": "내용",
8 | "latitude": 37.1231053,
9 | "longitude": 127.1231053,
10 | "tag": [
11 | "부산",
12 | "광안리",
13 | "바다"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PostList.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": [
5 | {
6 | "member" : {
7 | "id" : 1,
8 | "username" : "안유진",
9 | "introduce" : "안녕하세요, 아이브의 안유진입니다.",
10 | "profile_image_url" : "https://cdn.footballist.co.kr/news/photo/202307/170226_100422_1733.jpg"
11 | },
12 | "board" : {
13 | "id" : 1,
14 | "encoded_video_url" : "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8",
15 | "video_thumbnail_url" : "https://think-note.com/wp-content/uploads/2023/07/eta_3.jpg",
16 | "longitude" : 37.0532156213,
17 | "latitude" : 127.060123123,
18 | "title" : "최강 아이돌",
19 | "content" : "게시글 설명",
20 | "status": "COMPLETE"
21 | },
22 | "tag" : ["아이브", "yujin"]
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PostListEnd.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": [
5 |
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PostListMore.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "요청이 성공적으로 처리되었습니다.",
3 | "statusCode": 200,
4 | "data": [
5 | {
6 | "member" : {
7 | "id" : 2,
8 | "username" : "장원영",
9 | "introduce" : "안녕하세요, 아이브의 장원영입니다.",
10 | "profile_image_url" : "https://www.fnnews.com/resource/media/image/2023/10/17/202310171126334525_l.jpg"
11 | },
12 | "board" : {
13 | "id" : 2,
14 | "encoded_video_url" : "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8",
15 | "video_thumbnail_url" : "https://img.etoday.co.kr/pto_db/2022/11/600/20221108175829_1816470_1200_1800.jpg",
16 | "longitude" : 35.001828282,
17 | "latitude" : 100.060123123,
18 | "title" : "아이브의 멤버",
19 | "content" : "게시글 설명설명설명",
20 | "status": "COMPLETE"
21 | },
22 | "tag" : ["Ive", "wonyoung"]
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/PostsPage.json:
--------------------------------------------------------------------------------
1 | {
2 | "customCode": "SUCCESS",
3 | "message": "성공",
4 | "statusCode": 200,
5 | "data": {
6 | "lastId": 32,
7 | "boardsResDto": [
8 | {
9 | "member": {
10 | "id": 221,
11 | "username": "hwani",
12 | "introduce": "Hi, my name is hwani",
13 | "profile_image_url": "https://layover-profile-image.kr.obj..."
14 | },
15 | "board": {
16 | "id": 1,
17 | "encoded_video_url": "https://qc66zhsq1708.edge.naverncp.com/hls/fMG98Ec1UirV-awtm4qKJyhanmRFlPLZbTs_/layover-station/sv_AVC_HD, SD_1Pass_30fps.mp4/index.m3u8",
18 | "video_thumbnail_url": "https://layover-video-thumbnail.kr.obj...",
19 | "latitude": 37.0532156213,
20 | "longitude": 37.0532156213,
21 | "title": "붓산 광안리",
22 | "content": "날씨가 정말 좋았따이",
23 | "status": "COMPLETE"
24 | },
25 | "tag": [
26 | "tag1",
27 | "tag2"
28 | ]
29 | }
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/ReportPlaybackVideo.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "성공",
3 | "statusCode": 200,
4 | "data": {
5 | "memberId": 221,
6 | "boardId": 5,
7 | "reportType": "청소년에게 유해한 내용이에요"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/MockDatas/sample.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boostcampwm2023/iOS09-Layover/a3f2d39f67882d9d3512c1ebb926985df2609662/iOS/Layover/LayoverTests/Mocks/MockDatas/sample.jpeg
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Mocks/Workers/MockSettingWorker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockSettingWorker.swift
3 | // LayoverTests
4 | //
5 | // Created by 김인환 on 12/13/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 | @testable import Layover
9 | import Foundation
10 |
11 | final class MockSettingWorker: SettingWorkerProtocol {
12 |
13 | // MARK: - Methods
14 |
15 | func versionNumber() -> String? {
16 | "7.7.7"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iOS/Layover/LayoverTests/Stubs/StubAuthManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubAuthManager.swift
3 | // LayoverTests
4 | //
5 | // Created by 김인환 on 12/2/23.
6 | // Copyright © 2023 CodeBomber. All rights reserved.
7 | //
8 | @testable import Layover
9 | import Foundation
10 |
11 | class StubAuthManager: AuthManagerProtocol {
12 |
13 | // MARK: - Properties
14 |
15 | var accessToken: String? = "Fake Access Token"
16 | var refreshToken: String? = "Fake Refresh Token"
17 | var isLoggedIn: Bool? = true
18 | var loginType: LoginType? = .kakao
19 | var memberID: Int? = -1
20 |
21 | // MARK: - Methods
22 |
23 | func login(accessToken: String?, refreshToken: String?, loginType: LoginType?) {
24 | self.accessToken = accessToken
25 | self.refreshToken = refreshToken
26 | self.loginType = loginType
27 | isLoggedIn = true
28 | }
29 |
30 | func logout() {
31 | accessToken = nil
32 | refreshToken = nil
33 | memberID = nil
34 | loginType = nil
35 | isLoggedIn = false
36 | }
37 | }
38 |
--------------------------------------------------------------------------------