From 3ed05bab23663a713a78db41a53b32d4964fea61 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 8 Apr 2023 00:19:30 +0900 Subject: [PATCH 01/11] =?UTF-8?q?[Feat]=20#125=20-=20=ED=8E=B8=EC=A7=91?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Literal/ImageLiterals.swift | 2 ++ .../ic_frame_edit.imageset/Contents.json | 23 ++++++++++++++++++ .../ic_frame_edit.imageset/Frame 2064.png | Bin 0 -> 1054 bytes .../ic_frame_edit.imageset/Frame 2064@2x.png | Bin 0 -> 1986 bytes .../ic_frame_edit.imageset/Frame 2064@3x.png | Bin 0 -> 2850 bytes .../CourseStorage/VC/CourseStorageVC.swift | 4 +++ .../PrivateCourseListView.swift | 19 ++++++++++++--- 7 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Contents.json create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064@2x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064@3x.png diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index a70f0055..a0aad73b 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -43,6 +43,8 @@ enum ImageLiterals { static var icLocationOverlay: UIImage { .load(named: "ic_location_overlay") } static var icLogoCircle: UIImage { .load(named: "ic_logo_circle") } static var icMore: UIImage { .load(named: "ic_more") } + static var icFrameEdit: UIImage { .load(named: "ic_frame_edit") } + // img static var imgBackground: UIImage { .load(named: "img_background") } diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Contents.json new file mode 100644 index 00000000..b4faaa73 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 2064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 2064@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 2064@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4ce3c83fa2e33805ce5c2e01c5908b1b5c8f14 GIT binary patch literal 1054 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 U<+GEAT>t<807*qoM6N<$g6hku3jhEB literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_frame_edit.imageset/Frame 2064@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0b291a665d4f41dd148f1761c55014d30985e9 GIT binary patch literal 2850 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 A#Q*>R literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift index 85de924e..4ce9e851 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift @@ -39,6 +39,8 @@ final class CourseStorageVC: UIViewController { private lazy var viewPager = ViewPager(pageTitles: ["내가 그린 코스", "스크랩 코스"]) .addPagedView(pagedView: [privateCourseListView, scrapCourseListView]) + + // MARK: - View Life Cycle override func viewDidLoad() { @@ -122,6 +124,8 @@ extension CourseStorageVC { make.top.equalTo(naviBar.snp.bottom) make.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) } + + } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift index 3e20bc09..403f2072 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift @@ -27,6 +27,11 @@ final class PrivateCourseListView: UIView { $0.scrollDirection = .vertical } + private let frameEditButton = UIButton(type: .system).then { + $0.setImage(ImageLiterals.icFrameEdit, for: .normal) + $0.tintColor = .g1 + } + private lazy var courseListCollectionView = UICollectionView( frame: .zero, collectionViewLayout: collectionViewLayout @@ -83,14 +88,20 @@ extension PrivateCourseListView { } private func setLayout() { - self.addSubviews(courseListCollectionView) + self.addSubviews(frameEditButton,courseListCollectionView) courseListCollectionView.addSubviews(emptyView) - + + frameEditButton.snp.makeConstraints { make in + make.top.equalToSuperview().offset(11) + make.trailing.equalTo(self.safeAreaLayoutGuide).inset(16) + + } + courseListCollectionView.snp.makeConstraints { make in - make.top.equalToSuperview() + make.top.equalTo(frameEditButton.snp.bottom) make.leading.bottom.trailing.equalToSuperview() + } - emptyView.snp.makeConstraints { make in make.center.equalToSuperview() make.leading.trailing.equalToSuperview().inset(80) From e56b6b4e2dcbf898e88ebc6d03589fe066fcac83 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Mon, 17 Apr 2023 14:18:57 +0900 Subject: [PATCH 02/11] [Merge] #125 - Merge --- .../Runnect-iOS.xcodeproj/project.pbxproj | 12 ++++ .../Global/Literal/ImageLiterals.swift | 2 + .../img_apple_login.imageset/Contents.json | 23 ++++++++ .../img_apple_login.imageset/Group 9514.png | Bin 0 -> 1856 bytes .../Group 9514@2x.png | Bin 0 -> 3671 bytes .../Group 9514@3x.png | Bin 0 -> 5691 bytes .../img_kakao_login.imageset/Contents.json | 23 ++++++++ .../img_kakao_login.imageset/Kakao Login.png | Bin 0 -> 1808 bytes .../Kakao Login@2x.png | Bin 0 -> 3526 bytes .../Kakao Login@3x.png | Bin 0 -> 5374 bytes .../Global/Utils/RNUtils/UserManager.swift | 20 +++---- .../ResponseDto/GetNewTokenResponseDto.swift | 15 +++++ .../Network/Router/AuthRouter.swift | 13 ++++- .../Network/Router/CourseRouter.swift | 10 ++-- .../Network/Router/PublicCourseRouter.swift | 13 ++++- .../Network/Router/RecordRouter.swift | 6 +- .../Network/Router/ScrapRouter.swift | 6 +- .../Network/Router/StampRouter.swift | 8 ++- .../Network/Router/UserRouter.swift | 6 +- .../Network/Service/AuthInterceptor.swift | 55 ++++++++++++++++++ .../Network/Service/Providers.swift | 32 ++++++++++ .../CourseDetail/VC/CourseDetailVC.swift | 12 +--- .../Views/VC/CourseDiscoveryVC.swift | 24 ++++---- .../Views/VC/CourseSearchVC.swift | 8 +-- .../Views/VC/CourseUploadVC.swift | 5 +- .../Views/VC/MyCourseSelectVC.swift | 4 +- .../CourseDrawing/VC/CourseDrawingVC.swift | 4 +- .../CourseDrawing/VC/DepartureSearchVC.swift | 4 +- .../CourseStorage/VC/CourseStorageVC.swift | 8 +-- .../VC/InfoVC/ActivityRecordInfoVC.swift | 4 +- .../MyPage/VC/InfoVC/GoalRewardInfoVC.swift | 4 +- .../VC/InfoVC/UploadedCourseInfoVC.swift | 4 +- .../Presentation/MyPage/VC/MyPageVC.swift | 4 +- .../MyPage/VC/NicknameEditorVC.swift | 4 +- .../Running/VC/RunningRecordVC.swift | 4 +- .../Running/VC/RunningWaitingVC.swift | 8 +-- .../SignIn/VC/NickNameSetUpVC.swift | 4 +- .../SignIn/VC/SignInSocialLoginVC.swift | 38 ++++++------ .../Presentation/Splash/VC/SplashVC.swift | 14 ++++- 39 files changed, 280 insertions(+), 121 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@2x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Contents.json create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@3x.png create mode 100644 Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift create mode 100644 Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift create mode 100644 Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index a8ffdaee..4aeb993e 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -31,6 +31,8 @@ CE0D9FD329648DA300CEB5CD /* CustomAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0D9FD229648DA300CEB5CD /* CustomAlertVC.swift */; }; CE10065529680F7000FD31FB /* DepartureSearchingResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE10065429680F7000FD31FB /* DepartureSearchingResponseDto.swift */; }; CE1006572968230800FD31FB /* DepartureLocationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1006562968230800FD31FB /* DepartureLocationModel.swift */; }; + CE102C4829DB1D6B00E23E69 /* GetNewTokenResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */; }; + CE102C4A29DBAD3D00E23E69 /* AuthInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */; }; CE146770296568DC00DCEA1B /* RunTrackingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE14676F296568DC00DCEA1B /* RunTrackingVC.swift */; }; CE14677829658C7200DCEA1B /* Stopwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE14677729658C7200DCEA1B /* Stopwatch.swift */; }; CE14677A2965A80700DCEA1B /* CustomBottomSheetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1467792965A80700DCEA1B /* CustomBottomSheetVC.swift */; }; @@ -130,6 +132,7 @@ CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */; }; CEC2A6922962BE2900160BF7 /* DepartureSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */; }; CECA695C296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECA695B296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift */; }; + CEE59FDA29DD6F7D00C791F1 /* Providers.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE59FD929DD6F7D00C791F1 /* Providers.swift */; }; CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */; }; CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */; }; CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */; }; @@ -180,6 +183,8 @@ CE10065229680D4400FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10065429680F7000FD31FB /* DepartureSearchingResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchingResponseDto.swift; sourceTree = ""; }; CE1006562968230800FD31FB /* DepartureLocationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureLocationModel.swift; sourceTree = ""; }; + CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNewTokenResponseDto.swift; sourceTree = ""; }; + CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthInterceptor.swift; sourceTree = ""; }; CE14676F296568DC00DCEA1B /* RunTrackingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunTrackingVC.swift; sourceTree = ""; }; CE14677729658C7200DCEA1B /* Stopwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stopwatch.swift; sourceTree = ""; }; CE1467792965A80700DCEA1B /* CustomBottomSheetVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBottomSheetVC.swift; sourceTree = ""; }; @@ -283,6 +288,7 @@ CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = convertLocationObject.swift; sourceTree = ""; }; CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchVC.swift; sourceTree = ""; }; CECA695B296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateCourseNotUploadedResponseDto.swift; sourceTree = ""; }; + CEE59FD929DD6F7D00C791F1 /* Providers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Providers.swift; sourceTree = ""; }; CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingHomeVC.swift; sourceTree = ""; }; CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; @@ -373,6 +379,7 @@ isa = PBXGroup; children = ( A3D1A77D29CF09B600DD54EC /* SignInResponseDto.swift */, + CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */, ); path = ResponseDto; sourceTree = ""; @@ -891,6 +898,8 @@ isa = PBXGroup; children = ( CE6655BE295D82E200C64E12 /* .gitkeep */, + CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */, + CEE59FD929DD6F7D00C791F1 /* Providers.swift */, ); path = Service; sourceTree = ""; @@ -1313,6 +1322,7 @@ CE17F0382961BF8B00E1DED0 /* FontLiterals.swift in Sources */, CE6655E8295D889600C64E12 /* UISwitch+.swift in Sources */, CE0C23772966D64D00B45063 /* PageCVC.swift in Sources */, + CEE59FDA29DD6F7D00C791F1 /* Providers.swift in Sources */, CE5875A029601500005D967E /* Toast.swift in Sources */, CE40BB1E2968054F0030ABCA /* BaseResponse.swift in Sources */, CE14677C2965C1B100DCEA1B /* RunningRecordVC.swift in Sources */, @@ -1334,6 +1344,7 @@ CE6655FE295D912300C64E12 /* calculateTopInset.swift in Sources */, CEEC6B492961C5E200D00E1E /* SplashVC.swift in Sources */, CE6655D0295D85FF00C64E12 /* CancelBag.swift in Sources */, + CE102C4A29DBAD3D00E23E69 /* AuthInterceptor.swift in Sources */, A3BC2F432966A93100198261 /* CourseDetailVC.swift in Sources */, DAD5A3D8296C6D9600C8166B /* AdImageCollectionViewCell.swift in Sources */, CE18E890296C76C100FEB569 /* RNLocationModel.swift in Sources */, @@ -1391,6 +1402,7 @@ CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, A3BC2F34296303A600198261 /* GoalRewardInfoCVC.swift in Sources */, CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */, + CE102C4829DB1D6B00E23E69 /* GetNewTokenResponseDto.swift in Sources */, CE6655CA295D84DD00C64E12 /* UserDefaultKeyList.swift in Sources */, CE6655F2295D894D00C64E12 /* UIView+.swift in Sources */, CE9291252965C9FB0010959C /* CourseDetailInfoView.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index a0aad73b..d55aa829 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -70,6 +70,8 @@ enum ImageLiterals { static var imgSpaceship: UIImage { .load(named: "img_spaceship") } static var imgAppIcon: UIImage { .load(named: "img_app_icon") } static var imgAd: UIImage { .load(named: "img_ad") } + static var imgAppleLogin: UIImage { .load(named: "img_apple_login")} + static var imgKakaoLogin: UIImage { .load(named: "img_kakao_login")} } diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json new file mode 100644 index 00000000..e04c2538 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 9514.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 9514@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 9514@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png new file mode 100644 index 0000000000000000000000000000000000000000..ed5b189713bf00bd8caf09642ea8da7240f60186 GIT binary patch literal 1856 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 literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..b815b5b42f62be15bc181fc40c5551d44d347c71 GIT binary patch literal 5691 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 literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87ee34f5919b1994d3cf9860ee00fd80e486cea GIT binary patch literal 3526 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 - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var authProvider = Providers.authProvider @UserDefaultWrapper(key: "accessToken") public var accessToken @UserDefaultWrapper(key: "refreshToken") public var refreshToken @@ -35,7 +33,7 @@ final class UserManager { } func signIn(token: String, provider: String, completion: @escaping(Result) -> Void) { - signInProvider.request(.signIn(token: token, provider: provider)) { [weak self] response in + authProvider.request(.signIn(token: token, provider: provider)) { [weak self] response in guard let self = self else { return } switch response { case .success(let result): @@ -47,7 +45,7 @@ final class UserManager { self.accessToken = data.accessToken self.refreshToken = data.refreshToken self.isKakao = provider == "KAKAO" ? true : false - completion(.success(data.nickname ?? "")) + completion(.success(data.type)) // 로그인인지 회원가입인지 전달 } catch { print(error.localizedDescription) completion(.failure(.networkFail)) @@ -64,23 +62,19 @@ final class UserManager { } } - func autoSignIn(completion: @escaping(Result) -> Void) { - guard let accessToken = self.accessToken else { return } - guard let isKakao = self.isKakao else { return } - let provider = isKakao ? "KAKAO" : "APPLE" - signInProvider.request(.signIn(token: accessToken, provider: provider)) { [weak self] response in + func getNewToken(completion: @escaping(Result) -> Void) { + authProvider.request(.getNewToken) { [weak self] response in guard let self = self else { return } switch response { case .success(let result): let status = result.statusCode if 200..<300 ~= status { do { - let responseDto = try result.map(BaseResponse.self) + let responseDto = try result.map(BaseResponse.self) guard let data = responseDto.data else { return } self.accessToken = data.accessToken self.refreshToken = data.refreshToken - self.isKakao = provider == "KAKAO" ? true : false - completion(.success(data.nickname ?? "")) + completion(.success(true)) } catch { print(error.localizedDescription) completion(.failure(.networkFail)) diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift new file mode 100644 index 00000000..b30dcaf3 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift @@ -0,0 +1,15 @@ +// +// GetNewTokenResponseDto.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/03. +// + +import Foundation + +// MARK: - GetNewTokenResponseDto + +struct GetNewTokenResponseDto: Codable { + let accessToken: String + let refreshToken: String +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift index 06cfc2a8..17254689 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift @@ -11,6 +11,7 @@ import Moya enum AuthRouter { case signIn(token: String, provider: String) + case getNewToken } extension AuthRouter: TargetType { @@ -26,6 +27,8 @@ extension AuthRouter: TargetType { switch self { case .signIn: return "/auth" + case .getNewToken: + return "/auth/getNewToken" } } @@ -33,6 +36,8 @@ extension AuthRouter: TargetType { switch self { case .signIn: return .post + case .getNewToken: + return .get } } @@ -40,13 +45,19 @@ extension AuthRouter: TargetType { switch self { case .signIn(let token, let provider): return .requestParameters(parameters: ["token": token, "provider": provider], encoding: JSONEncoding.default) + case .getNewToken: + return .requestPlain } } var headers: [String: String]? { switch self { - case .signIn: + case .signIn, .getNewToken: return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift index dd36f92a..ca17dfe5 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift @@ -89,11 +89,13 @@ extension CourseRouter: TargetType { var headers: [String: String]? { switch self { case .uploadCourseDrawing: - return ["Content-Type": "multipart/form-data", - "accessToken": Config.accessToken, - "refreshToken": Config.refreshToken] + return ["Content-Type": "multipart/form-data"] default: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift index 57b20f0b..57143719 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift @@ -7,6 +7,7 @@ import Foundation import Moya + enum PublicCourseRouter { case getCourseData case getCourseSearchData(keyword: String) @@ -16,12 +17,14 @@ enum PublicCourseRouter { } extension PublicCourseRouter: TargetType { + var baseURL: URL { guard let url = URL(string: Config.baseURL) else {fatalError("baseURL could not be configured") } return url } + var path: String { switch self { case .getCourseData, .courseUploadingData: @@ -34,6 +37,7 @@ extension PublicCourseRouter: TargetType { return "/public-course/user" } } + var method: Moya.Method { switch self { case .getCourseData, .getCourseSearchData, .getUploadedCourseDetail, .getUploadedCourseInfo: @@ -41,8 +45,8 @@ extension PublicCourseRouter: TargetType { case .courseUploadingData: return .post } - } + var task: Moya.Task { switch self { case .getCourseSearchData(let keyword): @@ -56,10 +60,15 @@ extension PublicCourseRouter: TargetType { return .requestPlain } } + var headers: [String: String]? { switch self { default: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift index 3f896268..c635164c 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift @@ -57,7 +57,11 @@ extension RecordRouter: TargetType { var headers: [String: String]? { switch self { case .recordRunning, .getActivityRecordInfo: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift index fc23a636..8f0ca82d 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift @@ -53,7 +53,11 @@ extension ScrapRouter: TargetType { var headers: [String: String]? { switch self { case .createAndDeleteScrap, .getScrapCourse: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift index 36b09646..cb25ae3f 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift @@ -46,7 +46,11 @@ extension StampRouter: TargetType { var headers: [String: String]? { switch self { case .getGoalRewardInfo: - return Config.headerWithAccessToken + return Config.defaultHeader } - } + } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift index 9da8a5be..b3bcce38 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift @@ -49,6 +49,10 @@ extension UserRouter: TargetType { } var headers: [String: String]? { - return Config.headerWithAccessToken + return Config.defaultHeader + } + + var validationType: ValidationType { + return .successCodes } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift new file mode 100644 index 00000000..32017703 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift @@ -0,0 +1,55 @@ +// +// AuthInterceptor.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/04. +// + +import Foundation + +import Alamofire +import Moya + +///// 토큰 만료 시 자동으로 refresh를 위한 서버 통신 +final class AuthInterceptor: RequestInterceptor { + + static let shared = AuthInterceptor() + + private init() {} + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + guard urlRequest.url?.absoluteString.hasPrefix(Config.baseURL) == true, + let accessToken = UserManager.shared.accessToken, + let refreshToken = UserManager.shared.refreshToken + else { + completion(.success(urlRequest)) + return + } + + var urlRequest = urlRequest + urlRequest.setValue(accessToken, forHTTPHeaderField: "accessToken") + urlRequest.setValue(refreshToken, forHTTPHeaderField: "refreshToken") + print("adator 적용 \(urlRequest.headers)") + completion(.success(urlRequest)) + } + + func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { + print("retry 진입") + guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 + else { + completion(.doNotRetryWithError(error)) + return + } + + UserManager.shared.getNewToken { result in + switch result { + case .success: + print("Retry-토큰 재발급 성공") + completion(.retry) + case .failure(let error): + // 세션 만료 -> 로그인 화면으로 전환 + completion(.doNotRetryWithError(error)) + } + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift b/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift new file mode 100644 index 00000000..eeb361cc --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift @@ -0,0 +1,32 @@ +// +// Providers.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/05. +// + +import Foundation + +import Moya + +struct Providers { + static let departureSearchingProvider = MoyaProvider(withAuth: false) + static let authProvider = MoyaProvider(withAuth: true) + static let userProvider = MoyaProvider(withAuth: true) + static let courseProvider = MoyaProvider(withAuth: true) + static let publicCourseProvider = MoyaProvider(withAuth: true) + static let recordProvider = MoyaProvider(withAuth: true) + static let scrapProvider = MoyaProvider(withAuth: true) + static let stampProvider = MoyaProvider(withAuth: true) +} + +extension MoyaProvider { + convenience init(withAuth: Bool) { + if withAuth { + self.init(session: Session(interceptor: AuthInterceptor.shared), + plugins: [NetworkLoggerPlugin(verbose: true)]) + } else { + self.init() + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 728f789a..43b63349 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -16,17 +16,11 @@ final class CourseDetailVC: UIViewController { // MARK: - Properties - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var courseModel: Course? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift index 4686de86..e5e1eda2 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift @@ -15,13 +15,9 @@ import Moya final class CourseDiscoveryVC: UIViewController { // MARK: - Properties - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private var courseList = [PublicCourse]() @@ -32,8 +28,8 @@ final class CourseDiscoveryVC: UIViewController { $0.setImage(ImageLiterals.icSearch, for: .normal) $0.tintColor = .g1 } - private let plusButton = UIButton(type: .system).then { - $0.setImage(ImageLiterals.icPlus, for: .normal) + private let uploadButton = CustomButton(title: "업로드하기").then { + $0.layer.cornerRadius = 20 } // MARK: - collectionview @@ -88,10 +84,8 @@ extension CourseDiscoveryVC { } private func setAddTarget() { - self.searchButton.addTarget(self, action: #selector(pushToSearchVC), for: .touchUpInside) - self.plusButton.addTarget(self, action: #selector(pushToDiscoveryVC), for: .touchUpInside) - + self.uploadButton.addTarget(self, action: #selector(pushToDiscoveryVC), for: .touchUpInside) } } @@ -128,17 +122,19 @@ extension CourseDiscoveryVC { private func layout() { view.backgroundColor = .w1 mapCollectionView.backgroundColor = .w1 - view.addSubviews(plusButton, mapCollectionView) - view.bringSubviewToFront(plusButton) + view.addSubviews(uploadButton, mapCollectionView) + view.bringSubviewToFront(uploadButton) mapCollectionView.snp.makeConstraints { $0.top.equalTo(self.navibar.snp.bottom) $0.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) } - plusButton.snp.makeConstraints { make in + uploadButton.snp.makeConstraints { make in make.trailing.equalTo(self.view.safeAreaLayoutGuide).inset(16) make.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(20) + make.height.equalTo(40) + make.width.equalTo(136) } } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift index 9146e531..5d3d7fa4 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift @@ -15,13 +15,9 @@ final class CourseSearchVC: UIViewController { // MARK: - Properties - private let PublicCourseRouter = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseRouter = Providers.publicCourseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private var courseList = [PublicCourse]() private var keyword: String? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift index 4d5eaf5f..75a4b26e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift @@ -15,9 +15,8 @@ class CourseUploadVC: UIViewController { // MARK: - Properties // private var runningModel: RunningModel? - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider + private var courseModel: Course? private let courseTitleMaxLength = 20 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift index 902e38ca..d397bd9e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift @@ -14,9 +14,7 @@ class MyCourseSelectVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var courseList = [Course]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift index 417e95ef..a6e2456c 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift @@ -14,9 +14,7 @@ final class CourseDrawingVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var departureLocationModel: DepartureLocationModel? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift index 1ff6f618..d135000a 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift @@ -13,9 +13,7 @@ final class DepartureSearchVC: UIViewController { // MARK: - Properties - private let departureSearchingProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let departureSearchingProvider = Providers.departureSearchingProvider private var addressList = [KakaoAddressResult]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift index 4ce9e851..dd12a977 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift @@ -14,13 +14,9 @@ final class CourseStorageVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private let cancelBag = CancelBag() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift index 5dc24c5c..eab49a64 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift @@ -15,9 +15,7 @@ final class ActivityRecordInfoVC: UIViewController { // MARK: - Properties - private var recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var recordProvider = Providers.recordProvider private var activityRecordList = [ActivityRecord]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift index caed83c7..ecd9e045 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift @@ -14,9 +14,7 @@ import Moya final class GoalRewardInfoVC: UIViewController { // MARK: - Properties - private var stampProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var stampProvider = Providers.stampProvider var stampNameList: [GoalRewardInfoModel] = GoalRewardInfoModel.stampNameList diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift index 4dea323a..2a13d3d7 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift @@ -15,9 +15,7 @@ final class UploadedCourseInfoVC: UIViewController { // MARK: - Properties - private var uploadedCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var uploadedCourseProvider = Providers.publicCourseProvider private var uploadedCourseList = [PublicCourse]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift index d66fb775..e969717c 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift @@ -15,9 +15,7 @@ final class MyPageVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider let stampNameImageDictionary: [String: UIImage] = GoalRewardInfoModel.stampNameImageDictionary diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift index 5bd10471..d01a8c34 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift @@ -19,9 +19,7 @@ final class NicknameEditorVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider weak var delegate: NicknameEditorVCDelegate? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift index c0ee546f..108df439 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift @@ -15,9 +15,7 @@ final class RunningRecordVC: UIViewController { private var runningModel: RunningModel? - private let recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let recordProvider = Providers.recordProvider private let courseTitleMaxLength = 20 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift index 7bfa5151..c5f95be7 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift @@ -18,13 +18,9 @@ final class RunningWaitingVC: UIViewController { private var publicCourseId: Int? private var courseModel: Course? - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider - private let recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let recordProvider = Providers.recordProvider // MARK: - UI Components diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift index 6006e1e7..78d08a3b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift @@ -13,9 +13,7 @@ final class NickNameSetUpVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider private let nicknameMaxLength = 7 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift index 2d73d8ef..5509f4c9 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift @@ -33,18 +33,15 @@ final class SignInSocialLoginVC: UIViewController { $0.contentMode = .scaleAspectFill } - private lazy var kakaoLoginButton = UIButton(type: .system).then { - $0.setTitle("카카오로 로그인", for: .normal) - $0.titleLabel?.font = .b3 - $0.setTitleColor(.black, for: .normal) - $0.setBackgroundColor(UIColor(hex: "FEE500"), for: .normal) - $0.layer.cornerRadius = 7 - $0.setImage(ImageLiterals.icKakao, for: .normal) - $0.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: self.screenWidth * 0.5) - $0.tintColor = .black + private let appleLoginButton = UIButton(type: .custom).then { + $0.layer.cornerRadius = 8 + $0.setImage(ImageLiterals.imgAppleLogin, for: .normal) } - private let appleLoginButton = ASAuthorizationAppleIDButton() + private let kakaoLoginButton = UIButton(type: .custom).then { + $0.layer.cornerRadius = 8 + $0.setImage(ImageLiterals.imgKakaoLogin, for: .normal) + } override func viewDidLoad() { super.viewDidLoad() @@ -85,9 +82,8 @@ extension SignInSocialLoginVC { guard let oauthToken = oauthToken else { return } UserManager.shared.signIn(token: oauthToken.accessToken, provider: "KAKAO") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() @@ -105,9 +101,8 @@ extension SignInSocialLoginVC { guard let oauthToken = oauthToken else { return } UserManager.shared.signIn(token: oauthToken.accessToken, provider: "KAKAO") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() @@ -131,6 +126,12 @@ extension SignInSocialLoginVC { let nicknameSetUpVC = NickNameSetUpVC() self.navigationController?.pushViewController(nicknameSetUpVC, animated: true) } + + private func pushToTabBarController() { + let tabBarController = TabBarController() + guard let window = self.view.window else { return } + ViewControllerUtils.setRootViewController(window: window, viewController: tabBarController, withAnimation: true) + } } // MARK: - UI & Layout @@ -192,9 +193,8 @@ extension SignInSocialLoginVC: ASAuthorizationControllerPresentationContextProvi UserManager.shared.signIn(token: tokeStr, provider: "APPLE") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift index b8dc1c89..621e5052 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift @@ -11,7 +11,7 @@ import SnapKit import Then final class SplashVC: UIViewController { - + // MARK: - UI Components private let backgroundImageView = UIImageView().then { @@ -41,8 +41,16 @@ extension SplashVC { private func checkDidSignIn() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { if UserManager.shared.hasAccessToken { - // accessToken 재발급 - self.pushToTabBarController() + UserManager.shared.getNewToken { [weak self] result in + switch result { + case .success: + print("SplashVC-토큰 재발급 성공") + self?.pushToTabBarController() + case .failure(let error): + print(error) + self?.pushToSignInView() + } + } } else { self.pushToSignInView() } From bf2e163578bad9c88a97d740c7e87e2648ec8523 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Mon, 17 Apr 2023 14:27:15 +0900 Subject: [PATCH 03/11] =?UTF-8?q?[Feat]#125=20-=20=EC=8B=A0=EA=B3=A0?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EA=B5=AC=EA=B8=80?= =?UTF-8?q?=ED=8F=BC=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CourseDetail/VC/CourseDetailVC.swift | 17 ++++++++--------- .../CourseStorage/VC/CourseStorageVC.swift | 5 ----- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 43b63349..7a4798ba 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -11,6 +11,7 @@ import SnapKit import Then import NMapsMap import Moya +import SafariServices final class CourseDetailVC: UIViewController { @@ -100,7 +101,6 @@ final class CourseDetailVC: UIViewController { $0.isScrollEnabled = false $0.sizeToFit() } - // MARK: - View Life Cycle override func viewDidLoad() { @@ -128,16 +128,15 @@ extension CourseDetailVC { @objc func moreButtonDidTap() { let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - - let saveAction = UIAlertAction(title: "저장하기", style: .default, handler: nil) - let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in - //report action + let formUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") + let formSafariView: SFSafariViewController = SFSafariViewController(url: formUrl! as URL) + let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(formSafariView, animated: true, completion: nil) }) - let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) - - [ saveAction, reportAction, cancelAction ].forEach { alertController.addAction($0) } + let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) - present(alertController, animated: true, completion: nil) + [ reportAction, cancelAction ].forEach { alertController.addAction($0) } + present(alertController, animated: true, completion: nil) } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift index dd12a977..d7eb50bb 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift @@ -34,9 +34,6 @@ final class CourseStorageVC: UIViewController { private lazy var viewPager = ViewPager(pageTitles: ["내가 그린 코스", "스크랩 코스"]) .addPagedView(pagedView: [privateCourseListView, scrapCourseListView]) - - - // MARK: - View Life Cycle override func viewDidLoad() { @@ -120,8 +117,6 @@ extension CourseStorageVC { make.top.equalTo(naviBar.snp.bottom) make.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) } - - } } From 5a34c1ca4c971a3d750b76de8345f2445603764f Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Mon, 17 Apr 2023 15:41:27 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=20[Feat]#125=20-=20=EC=B4=9D=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=EB=9D=BC=EB=B2=A8=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PrivateCourseListView.swift | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift index 403f2072..21b963ff 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift @@ -26,11 +26,28 @@ final class PrivateCourseListView: UIView { private let collectionViewLayout = UICollectionViewFlowLayout().then { $0.scrollDirection = .vertical } - + private let beforeEditTopView = UIView().then{ + $0.backgroundColor = .clear + } private let frameEditButton = UIButton(type: .system).then { $0.setImage(ImageLiterals.icFrameEdit, for: .normal) $0.tintColor = .g1 } + private let totalCourseNum = UILabel().then{ + $0.text = "총 100개" + $0.font = .b6 + $0.textColor = .g2 + } + +// private let afterEditTopView = UIView() +// private let selectCouseLabel = UILabel().then { +// $0.text = "코스 선택" +// $0.font = .b6 +// $0.textColor = .g2 +// } + + + private lazy var courseListCollectionView = UICollectionView( frame: .zero, @@ -88,13 +105,20 @@ extension PrivateCourseListView { } private func setLayout() { - self.addSubviews(frameEditButton,courseListCollectionView) + self.addSubviews(beforeEditTopView,courseListCollectionView) courseListCollectionView.addSubviews(emptyView) + beforeEditTopView.addSubviews(frameEditButton,totalCourseNum) + + beforeEditTopView.snp.makeConstraints{ make in make.top.top.equalToSuperview().offset(11)} frameEditButton.snp.makeConstraints { make in - make.top.equalToSuperview().offset(11) + make.top.equalToSuperview().offset(1) make.trailing.equalTo(self.safeAreaLayoutGuide).inset(16) - + } + + totalCourseNum.snp.makeConstraints { make in + make.top.equalToSuperview().offset(1) + make.leading.equalTo(self.safeAreaLayoutGuide).offset(16) } courseListCollectionView.snp.makeConstraints { make in From f51742961fb94ca5d9885e838c6d8a73109aed81 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Fri, 21 Apr 2023 21:58:04 +0900 Subject: [PATCH 05/11] =?UTF-8?q?[Feat]=20#125=20-=20CourseDetailVC?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyPage/VC/InfoVC/UploadedCourseInfoVC.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift index 2a13d3d7..aaa53aa9 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift @@ -119,6 +119,16 @@ extension UploadedCourseInfoVC: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return uploadedCourseInset } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + + let courseDetailVC = CourseDetailVC() + let courseModel = uploadedCourseList[indexPath.item] + courseDetailVC.setCourseId(courseId: courseModel.courseId, publicCourseId: courseModel.id) + courseDetailVC.hidesBottomBarWhenPushed = true + self.navigationController?.pushViewController(courseDetailVC, animated: true) + + } } // MARK: - UICollectionViewDataSource From e5471de4fa4468b22c34e47987d215cd6c44b5dd Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 09:15:52 +0900 Subject: [PATCH 06/11] =?UTF-8?q?[Feat]=20#125=20-=20CourseDetailVC=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Literal/ImageLiterals.swift | 3 ++ .../CourseDetail/VC/CourseDetailVC.swift | 42 ++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index c625596e..58eb8944 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -44,6 +44,9 @@ enum ImageLiterals { static var icLogoCircle: UIImage { .load(named: "ic_logo_circle") } static var icMore: UIImage { .load(named: "ic_more") } static var icPlus: UIImage { .load(named: "ic_plus") } + static var icFrameEdit: UIImage { + .load(named: "ic_frame_edit") + } // img static var imgBackground: UIImage { .load(named: "img_background") } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 7a4798ba..9e6be8f5 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -27,6 +27,7 @@ final class CourseDetailVC: UIViewController { private var courseId: Int? private var publicCourseId: Int? + private var userId: Int? // MARK: - UI Components private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton) @@ -126,19 +127,33 @@ extension CourseDetailVC { } @objc func moreButtonDidTap() { - - let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - let formUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") - let formSafariView: SFSafariViewController = SFSafariViewController(url: formUrl! as URL) - let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in - self.present(formSafariView, animated: true, completion: nil) -}) + //Todo : case를 2개를 나눠서, userID가 나인경우에는 editAction,이외에는 신고액션 + // 삭제 & 수정 올라오는거(유저아이디가 나인경우) + let userId = ""//본인아이디 let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) - - [ reportAction, cancelAction ].forEach { alertController.addAction($0) } - present(alertController, animated: true, completion: nil) - - } + if "유저아이디" == "본인아이디" { + let editAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + let courseUploadVC = CourseUploadVC() + let editAction = UIAlertAction(title: "수정하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(courseUploadVC, animated: true, completion: nil) + }) + let delateAction = UIAlertAction(title: "삭제하기", style: .cancel, handler: nil) + [ editAction, delateAction, cancelAction].forEach { editAlertController.addAction($0) } + present(editAlertController, animated: true, completion: nil) + + } else { + // 신고폼 올라오는 거(유저아이디가 내가 아닌 경우) + let reportAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + let formUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") + let formSafariView: SFSafariViewController = SFSafariViewController(url: formUrl! as URL) + let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(formSafariView, animated: true, completion: nil) + }) + [ reportAction, cancelAction ].forEach { reportAlertController.addAction($0) } + present(reportAlertController, animated: true, completion: nil) + } + }; + private func pushToCountDownVC() { guard let courseModel = self.courseModel, @@ -173,10 +188,9 @@ extension CourseDetailVC { func setData(model: UploadedCourseDetailResponseDto) { self.mapImageView.setImage(with: model.publicCourse.image) self.profileImageView.image = GoalRewardInfoModel.stampNameImageDictionary[model.user.image] - self.profileNameLabel.text = model.user.nickname + self.profileNameLabel.text = model.user.nickname //유저닉네임 self.runningLevelLabel.text = "Lv. \(model.user.level)" self.courseTitleLabel.text = model.publicCourse.title - guard let scrap = model.publicCourse.scrap else { return } self.likeButton.isSelected = scrap From 7dc094df33818f3490f008ebd4ffcadc11d67578 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 09:24:47 +0900 Subject: [PATCH 07/11] =?UTF-8?q?[Feat]=20#125=20-=20Dto=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj | 12 ++++++++++++ .../RequestDto/EditCourseReguestDto.swift | 14 ++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index ecd3af5e..3aa90a8b 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -145,6 +145,7 @@ CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */; }; CEF3CD9A296DB305002723A1 /* CourseDetailResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */; }; CEFA9A2F29FC263700F2D0CF /* UserDeleteResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */; }; + DA0587F22A05D54100B72869 /* EditCourseReguestDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */; }; DA20D847296697A600F1581F /* MyCourseSelectVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D846296697A600F1581F /* MyCourseSelectVC.swift */; }; DA20D849296697B400F1581F /* CourseUploadVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D848296697B400F1581F /* CourseUploadVC.swift */; }; DA20D84E2966A9B300F1581F /* CourseSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */; }; @@ -307,6 +308,7 @@ CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDetailResponseDto.swift; sourceTree = ""; }; CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDeleteResponseDto.swift; sourceTree = ""; }; + DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCourseReguestDto.swift; sourceTree = ""; }; DA20D846296697A600F1581F /* MyCourseSelectVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCourseSelectVC.swift; sourceTree = ""; }; DA20D848296697B400F1581F /* CourseUploadVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseUploadVC.swift; sourceTree = ""; }; DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseSearchVC.swift; sourceTree = ""; }; @@ -441,6 +443,7 @@ CE10063329680BFD00FD31FB /* CourseDetailDto */ = { isa = PBXGroup; children = ( + DA0587F02A05D52100B72869 /* RequestDto */, CE4942AB296FCD1000736701 /* ResponseDto */, ); path = CourseDetailDto; @@ -1144,6 +1147,14 @@ path = VC; sourceTree = ""; }; + DA0587F02A05D52100B72869 /* RequestDto */ = { + isa = PBXGroup; + children = ( + DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */, + ); + path = RequestDto; + sourceTree = ""; + }; DA97A029296DC2020086760E /* RequestDto */ = { isa = PBXGroup; children = ( @@ -1423,6 +1434,7 @@ CE17F02D2961BBA100E1DED0 /* ColorLiterals.swift in Sources */, CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, + DA0587F22A05D54100B72869 /* EditCourseReguestDto.swift in Sources */, A3C2CACE29E313CC00EC525B /* SettingVC.swift in Sources */, CE21C02E299E601700F62AF5 /* StampRouter.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift new file mode 100644 index 00000000..70fb6e6c --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift @@ -0,0 +1,14 @@ +// +// EditCourseReguestDto.swift +// Runnect-iOS +// +// Created by YEONOO on 2023/05/06. +// + +import Foundation + +// MARK: - EditCourseReguestDto + +struct EditCourseReguestDto: Codable { + let title, description: String +} From 5ccec823384dba916829d46cadc643f4affc6ec7 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 09:54:04 +0900 Subject: [PATCH 08/11] =?UTF-8?q?[Feat]=20#125=20-=20UpdateCourse=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS/Network/Router/PublicCourseRouter.swift | 7 +++++++ .../Presentation/CourseDetail/VC/CourseDetailVC.swift | 1 + 2 files changed, 8 insertions(+) diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift index 57143719..8e843d7e 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift @@ -14,6 +14,7 @@ enum PublicCourseRouter { case courseUploadingData(param: CourseUploadingRequestDto) case getUploadedCourseDetail(publicCourseId: Int) case getUploadedCourseInfo + case updatePublicCourse(publicCousrseId: Int, param: EditCourseReguestDto) } extension PublicCourseRouter: TargetType { @@ -35,6 +36,8 @@ extension PublicCourseRouter: TargetType { return "/public-course/detail/\(publicCourseId)" case .getUploadedCourseInfo: return "/public-course/user" + case .updatePublicCourse(let publicCourseId ): + return "/public-course/\(publicCourseId)" } } @@ -44,6 +47,8 @@ extension PublicCourseRouter: TargetType { return .get case .courseUploadingData: return .post + case .updatePublicCourse: + return .patch } } @@ -56,6 +61,8 @@ extension PublicCourseRouter: TargetType { return .requestParameters(parameters: try param.asParameter(), encoding: JSONEncoding.default) } catch { fatalError("Encoding 실패")} + case .updatePublicCourse(let publicCourseId): + return .requestJSONEncodable(publicCourseId) case .getCourseData, .getUploadedCourseDetail, .getUploadedCourseInfo: return .requestPlain } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 9e6be8f5..2292804e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -129,6 +129,7 @@ extension CourseDetailVC { @objc func moreButtonDidTap() { //Todo : case를 2개를 나눠서, userID가 나인경우에는 editAction,이외에는 신고액션 // 삭제 & 수정 올라오는거(유저아이디가 나인경우) + //UploadedCourseDetailResponseDto 에서 유저정보 가져오는 법 let userId = ""//본인아이디 let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) if "유저아이디" == "본인아이디" { From 2e9ac3dc2289975a99f1b548f714380d41103490 Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 16:46:03 +0900 Subject: [PATCH 09/11] =?UTF-8?q?[Feat]=20#125=20-=20=EA=B8=80=EC=88=98?= =?UTF-8?q?=EC=A0=95=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 12 +- .../Global/UIComponents/RNAlertVC.swift | 6 +- ...stDto.swift => EditCourseRequestDto.swift} | 2 +- .../UploadedCourseDetailResponseDto.swift | 1 + .../Network/Router/PublicCourseRouter.swift | 13 +- .../CourseDetail/VC/CourseDetailVC.swift | 104 ++++-- .../CourseDetail/VC/CourseEditVC.swift | 353 ++++++++++++++++++ .../Views/VC/CourseUploadVC.swift | 1 - .../VC/InfoVC/UploadedCourseInfoVC.swift | 1 - 9 files changed, 447 insertions(+), 46 deletions(-) rename Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/{EditCourseReguestDto.swift => EditCourseRequestDto.swift} (82%) create mode 100644 Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 3aa90a8b..12388f13 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -145,7 +145,8 @@ CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */; }; CEF3CD9A296DB305002723A1 /* CourseDetailResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */; }; CEFA9A2F29FC263700F2D0CF /* UserDeleteResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */; }; - DA0587F22A05D54100B72869 /* EditCourseReguestDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */; }; + DA0587F22A05D54100B72869 /* EditCourseRequestDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0587F12A05D54100B72869 /* EditCourseRequestDto.swift */; }; + DA0587F42A05DEC000B72869 /* CourseEditVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0587F32A05DEC000B72869 /* CourseEditVC.swift */; }; DA20D847296697A600F1581F /* MyCourseSelectVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D846296697A600F1581F /* MyCourseSelectVC.swift */; }; DA20D849296697B400F1581F /* CourseUploadVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D848296697B400F1581F /* CourseUploadVC.swift */; }; DA20D84E2966A9B300F1581F /* CourseSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */; }; @@ -308,7 +309,8 @@ CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = ""; }; CEF3CD99296DB305002723A1 /* CourseDetailResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDetailResponseDto.swift; sourceTree = ""; }; CEFA9A2E29FC263700F2D0CF /* UserDeleteResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDeleteResponseDto.swift; sourceTree = ""; }; - DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCourseReguestDto.swift; sourceTree = ""; }; + DA0587F12A05D54100B72869 /* EditCourseRequestDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCourseRequestDto.swift; sourceTree = ""; }; + DA0587F32A05DEC000B72869 /* CourseEditVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseEditVC.swift; sourceTree = ""; }; DA20D846296697A600F1581F /* MyCourseSelectVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCourseSelectVC.swift; sourceTree = ""; }; DA20D848296697B400F1581F /* CourseUploadVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseUploadVC.swift; sourceTree = ""; }; DA20D84D2966A9B300F1581F /* CourseSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseSearchVC.swift; sourceTree = ""; }; @@ -722,6 +724,7 @@ isa = PBXGroup; children = ( A3BC2F422966A93100198261 /* CourseDetailVC.swift */, + DA0587F32A05DEC000B72869 /* CourseEditVC.swift */, ); path = VC; sourceTree = ""; @@ -1150,7 +1153,7 @@ DA0587F02A05D52100B72869 /* RequestDto */ = { isa = PBXGroup; children = ( - DA0587F12A05D54100B72869 /* EditCourseReguestDto.swift */, + DA0587F12A05D54100B72869 /* EditCourseRequestDto.swift */, ); path = RequestDto; sourceTree = ""; @@ -1376,6 +1379,7 @@ A3F67AE2296D33AC001598A2 /* MyPageDto.swift in Sources */, CE591EA1296D5EB5000FCBB3 /* PrivateCourseResponseDto.swift in Sources */, A3BC2F3F2964706100198261 /* UploadedCourseInfoCVC.swift in Sources */, + DA0587F42A05DEC000B72869 /* CourseEditVC.swift in Sources */, CE6655FE295D912300C64E12 /* calculateTopInset.swift in Sources */, CEEC6B492961C5E200D00E1E /* SplashVC.swift in Sources */, CE6655D0295D85FF00C64E12 /* CancelBag.swift in Sources */, @@ -1434,7 +1438,7 @@ CE17F02D2961BBA100E1DED0 /* ColorLiterals.swift in Sources */, CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, - DA0587F22A05D54100B72869 /* EditCourseReguestDto.swift in Sources */, + DA0587F22A05D54100B72869 /* EditCourseRequestDto.swift in Sources */, A3C2CACE29E313CC00EC525B /* SettingVC.swift in Sources */, CE21C02E299E601700F62AF5 /* StampRouter.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift index fe610b6e..70da2d1a 100644 --- a/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/RNAlertVC.swift @@ -25,6 +25,8 @@ final class RNAlertVC: UIViewController { private let descriptionLabel = UILabel().then { $0.font = .b4 $0.textColor = .g2 + $0.numberOfLines = 0 + $0.textAlignment = .center } private lazy var yesButton = UIButton(type: .custom).then { @@ -105,7 +107,7 @@ extension RNAlertVC { make.centerX.equalToSuperview() make.centerY.equalToSuperview() make.leading.trailing.equalToSuperview().inset(30) - make.height.equalTo(126) +// make.height.equalTo(126) } containerView.addSubviews(descriptionLabel, yesButton, noButton) @@ -116,6 +118,7 @@ extension RNAlertVC { } noButton.snp.makeConstraints { make in + make.top.equalTo(descriptionLabel.snp.bottom).offset(20) make.leading.equalToSuperview().offset(16) make.trailing.equalTo(containerView.snp.centerX).offset(-4) make.height.equalTo(44) @@ -124,6 +127,7 @@ extension RNAlertVC { } yesButton.snp.makeConstraints { make in + make.top.equalTo(noButton.snp.top) make.trailing.equalToSuperview().inset(16) make.leading.equalTo(containerView.snp.centerX).offset(4) make.height.equalTo(44) diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseRequestDto.swift similarity index 82% rename from Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift rename to Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseRequestDto.swift index 70fb6e6c..30939fcd 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseReguestDto.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/RequestDto/EditCourseRequestDto.swift @@ -9,6 +9,6 @@ import Foundation // MARK: - EditCourseReguestDto -struct EditCourseReguestDto: Codable { +struct EditCourseRequestDto: Codable { let title, description: String } diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/ResponseDto/UploadedCourseDetailResponseDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/ResponseDto/UploadedCourseDetailResponseDto.swift index 4f973bd2..0c1de183 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/ResponseDto/UploadedCourseDetailResponseDto.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/CourseDetailDto/ResponseDto/UploadedCourseDetailResponseDto.swift @@ -20,4 +20,5 @@ struct UploadUser: Codable { let nickname: String let level: Int let image: String + let isNowUser: Bool? } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift index 8e843d7e..bf710584 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift @@ -14,8 +14,8 @@ enum PublicCourseRouter { case courseUploadingData(param: CourseUploadingRequestDto) case getUploadedCourseDetail(publicCourseId: Int) case getUploadedCourseInfo - case updatePublicCourse(publicCousrseId: Int, param: EditCourseReguestDto) -} + case updatePublicCourse(publicCourseId: Int, editCourseRequestDto: EditCourseRequestDto) +} extension PublicCourseRouter: TargetType { @@ -36,7 +36,7 @@ extension PublicCourseRouter: TargetType { return "/public-course/detail/\(publicCourseId)" case .getUploadedCourseInfo: return "/public-course/user" - case .updatePublicCourse(let publicCourseId ): + case .updatePublicCourse(let publicCourseId, _): return "/public-course/\(publicCourseId)" } } @@ -61,8 +61,11 @@ extension PublicCourseRouter: TargetType { return .requestParameters(parameters: try param.asParameter(), encoding: JSONEncoding.default) } catch { fatalError("Encoding 실패")} - case .updatePublicCourse(let publicCourseId): - return .requestJSONEncodable(publicCourseId) + case .updatePublicCourse(_, let param): + do { + return .requestParameters(parameters: try param.asParameter(), encoding: JSONEncoding.default) + } catch { + fatalError("Encoding 실패")} case .getCourseData, .getUploadedCourseDetail, .getUploadedCourseInfo: return .requestPlain } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 2292804e..abbac2ca 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -25,9 +25,11 @@ final class CourseDetailVC: UIViewController { private var courseModel: Course? + private var uploadedCourseDetailModel: UploadedCourseDetailResponseDto? + private var courseId: Int? private var publicCourseId: Int? - private var userId: Int? + private var isMyCourse: Bool? // MARK: - UI Components private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton) @@ -80,7 +82,7 @@ final class CourseDetailVC: UIViewController { $0.textColor = .g1 $0.font = .h4 } - + private let courseDistanceInfoView = CourseDetailInfoView(title: "거리", description: "0.0km") private let courseDepartureInfoView = CourseDetailInfoView(title: "출발지", description: "위치") @@ -103,7 +105,7 @@ final class CourseDetailVC: UIViewController { $0.sizeToFit() } // MARK: - View Life Cycle - + override func viewDidLoad() { super.viewDidLoad() setNavigationBar() @@ -127,44 +129,49 @@ extension CourseDetailVC { } @objc func moreButtonDidTap() { - //Todo : case를 2개를 나눠서, userID가 나인경우에는 editAction,이외에는 신고액션 - // 삭제 & 수정 올라오는거(유저아이디가 나인경우) - //UploadedCourseDetailResponseDto 에서 유저정보 가져오는 법 - let userId = ""//본인아이디 + guard let isMyCourse = self.isMyCourse, let uploadedCourseDetailModel = self.uploadedCourseDetailModel else { return } + let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) - if "유저아이디" == "본인아이디" { - let editAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - let courseUploadVC = CourseUploadVC() - let editAction = UIAlertAction(title: "수정하기", style: .destructive, handler: {(_: UIAlertAction!) in - self.present(courseUploadVC, animated: true, completion: nil) - }) - let delateAction = UIAlertAction(title: "삭제하기", style: .cancel, handler: nil) - [ editAction, delateAction, cancelAction].forEach { editAlertController.addAction($0) } - present(editAlertController, animated: true, completion: nil) - - } else { - // 신고폼 올라오는 거(유저아이디가 내가 아닌 경우) - let reportAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - let formUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") - let formSafariView: SFSafariViewController = SFSafariViewController(url: formUrl! as URL) - let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in - self.present(formSafariView, animated: true, completion: nil) - }) - [ reportAction, cancelAction ].forEach { reportAlertController.addAction($0) } - present(reportAlertController, animated: true, completion: nil) - } - }; + if isMyCourse == true { + let editAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + let courseEditVC = CourseEditVC() + courseEditVC.loadData(model: uploadedCourseDetailModel) + courseEditVC.publicCourseId = self.publicCourseId + let editAction = UIAlertAction(title: "수정하기", style: .default, handler: {(_: UIAlertAction!) in + self.navigationController?.pushViewController(courseEditVC, animated: false) + }) + let delateVC = RNAlertVC(description: "코스를 정말로 삭제하시겠어요?") + delateVC.rightButtonTapAction = { [weak self] in +// self?.delateCourse() + } + delateVC.modalPresentationStyle = .overFullScreen + let delateAction = UIAlertAction(title: "삭제하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(delateVC, animated: true, completion: nil)}) + [ editAction, delateAction, cancelAction].forEach { editAlertController.addAction($0) } + present(editAlertController, animated: false, completion: nil) + } else { + // 신고폼 올라오는 거(유저아이디가 내가 아닌 경우) + let reportAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + let formUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") + let formSafariView: SFSafariViewController = SFSafariViewController(url: formUrl! as URL) + let reportAction = UIAlertAction(title: "신고하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(formSafariView, animated: true, completion: nil) + }) + [ reportAction, cancelAction ].forEach { reportAlertController.addAction($0) } + present(reportAlertController, animated: true, completion: nil) + } + } private func pushToCountDownVC() { guard let courseModel = self.courseModel, let path = courseModel.path, let distance = courseModel.distance else { return } - + let countDownVC = CountDownVC() let locations = path.map { NMGLatLng(lat: $0[0], lng: $0[1]) } - + let runningModel = RunningModel(courseId: self.courseId, publicCourseId: self.publicCourseId, locations: locations, @@ -187,11 +194,13 @@ extension CourseDetailVC { } func setData(model: UploadedCourseDetailResponseDto) { + self.uploadedCourseDetailModel = model self.mapImageView.setImage(with: model.publicCourse.image) self.profileImageView.image = GoalRewardInfoModel.stampNameImageDictionary[model.user.image] self.profileNameLabel.text = model.user.nickname //유저닉네임 self.runningLevelLabel.text = "Lv. \(model.user.level)" self.courseTitleLabel.text = model.publicCourse.title + self.isMyCourse = model.user.isNowUser guard let scrap = model.publicCourse.scrap else { return } self.likeButton.isSelected = scrap @@ -310,12 +319,12 @@ extension CourseDetailVC { make.top.equalTo(firstHorizontalDivideLine.snp.bottom).offset(16) make.leading.equalTo(view.safeAreaLayoutGuide).offset(16) } - + courseDetailStackView.snp.makeConstraints { make in make.top.equalTo(courseTitleLabel.snp.bottom).offset(19) make.leading.trailing.equalToSuperview().inset(16) } - + secondHorizontalDivideLine.snp.makeConstraints { make in make.top.equalTo(courseDetailStackView.snp.bottom).offset(27) make.leading.trailing.equalTo(view.safeAreaLayoutGuide) @@ -412,3 +421,32 @@ extension CourseDetailVC { } } } + +extension CourseDetailVC { + private func delateCourse() { + // guard let courseId = courseModel?.id else { return } + // let requsetDto = CourseUploadingRequestDto(courseId: courseId, title: titletext, description: descriptiontext) + // + // LoadingIndicator.showLoading() + // PublicCourseProvider.request(.courseUploadingData(param: requsetDto)) { [weak self] response in + // LoadingIndicator.hideLoading() + // guard let self = self else { return } + // switch response { + // case .success(let result): + // let status = result.statusCode + // if 200..<300 ~= status { + // self.navigationController?.popToRootViewController(animated: true) + // } + // if status >= 400 { + // print("400 error") + // self.showNetworkFailureToast() + // } + // case .failure(let error): + // print(error.localizedDescription) + // self.showNetworkFailureToast() + // } + // } + // } + // } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift new file mode 100644 index 00000000..0396329a --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift @@ -0,0 +1,353 @@ +// +// CourseEditVC.swift +// Runnect-iOS +// +// Created by YEONOO on 2023/05/06. +// + + +import UIKit + +import SnapKit +import Then +import Moya + +class CourseEditVC: UIViewController { + + // MARK: - Properties + private let PublicCourseProvider = Providers.publicCourseProvider + + private let courseTitleMaxLength = 20 + var publicCourseId: Int? + + // MARK: - UI Components + + private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("") + private let buttonContainerView = UIView() + private let editButton = CustomButton(title: "완료").setEnabled(false) + + private lazy var scrollView = UIScrollView() + private let mapImageView = UIImageView().then { + $0.image = UIImage(named: "") + } + private let courseTitleTextField = UITextField().then { + $0.attributedPlaceholder = NSAttributedString( + string: "글 제목", + attributes: [.font: UIFont.h4, .foregroundColor: UIColor.g3] + ) + $0.font = .h4 + $0.textColor = .g1 + $0.addLeftPadding(width: 2) + } + private let dividerView = UIView().then { + $0.backgroundColor = .g5 + } + private let distanceInfoView = CourseDetailInfoView(title: "거리", description: "0.0km") + private let departureInfoView = CourseDetailInfoView(title: "출발지", description: "") + private let placeholder = "코스에 대한 소개를 적어주세요.(난이도/풍경/지형)" + + let activityTextView = UITextView().then { + $0.font = .b4 + $0.backgroundColor = .m3 + $0.tintColor = .m1 + $0.textContainerInset = UIEdgeInsets(top: 14, left: 12, bottom: 14, right: 12) + } + + // MARK: - Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + setNavigationBar() + setUI() + setLayout() + setupTextView() + setAddTarget() + setKeyboardNotification() + setTapGesture() + addKeyboardObserver() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + self.tabBarController?.tabBar.isHidden = false + } + + deinit { + NotificationCenter.default.removeObserver(self) + } +} + +// MARK: - Methods + +extension CourseEditVC { + private func setAddTarget() { + self.courseTitleTextField.addTarget(self, action: #selector(textFieldTextDidChange), for: .editingChanged) + self.editButton.addTarget(self, action: #selector(editButtonDidTap), for: .touchUpInside) + } + + // data 그대로 load하기 + func loadData(model: UploadedCourseDetailResponseDto) { + mapImageView.setImage(with: model.publicCourse.image) + courseTitleTextField.text = model.publicCourse.title + distanceInfoView.setDescriptionText(description: "\(model.publicCourse.distance ?? 0.0)") + let departure = "\(model.publicCourse.departure.region) \(model.publicCourse.departure.city)" + departureInfoView.setDescriptionText(description: departure) + + activityTextView.text = model.publicCourse.description + } + + // 키보드가 올라오면 scrollView 위치 조정 + private func setKeyboardNotification() { + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillShow), + name: UIResponder.keyboardWillShowNotification, + object: nil) + + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillHide), + name: UIResponder.keyboardWillHideNotification, + object: nil) + } + + // 화면 터치 시 키보드 내리기 + private func setTapGesture() { + let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing)) + tap.cancelsTouchesInView = false + view.addGestureRecognizer(tap) + } + + private func addKeyboardObserver() { + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillShow), + name: UIResponder.keyboardWillShowNotification, + object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillHide), + name: UIResponder.keyboardWillHideNotification, + object: nil) + } +} +// MARK: - @objc Function + +extension CourseEditVC { + @objc private func textFieldTextDidChange() { + guard let text = courseTitleTextField.text else { return } + + if text.count > courseTitleMaxLength { + let index = text.index(text.startIndex, offsetBy: courseTitleMaxLength) + let newString = text[text.startIndex.. 150 { + activityTextView.deleteBackward() + } + } + func textViewDidEndEditing(_ textView: UITextView) { + if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || textView.text == placeholder { + activityTextView.textColor = .g3 + activityTextView.text = placeholder + } + } +} + +// MARK: - Network + +extension CourseEditVC { + private func editCourse() { + guard let titletext = courseTitleTextField.text else { return } + guard let descriptiontext = activityTextView.text else { return } + guard let publicCourseId = publicCourseId else { return } + let requsetDto = EditCourseRequestDto(title: titletext, description: descriptiontext) + + LoadingIndicator.showLoading() + PublicCourseProvider.request(.updatePublicCourse(publicCourseId: publicCourseId, editCourseRequestDto: requsetDto)) { [weak self] response in + LoadingIndicator.hideLoading() + guard let self = self else { return } + switch response { + case .success(let result): + let status = result.statusCode + if 200..<300 ~= status { + self.navigationController?.popViewController(animated: true) + } + if status >= 400 { + print("400 error") + self.showNetworkFailureToast() + } + case .failure(let error): + print(error.localizedDescription) + self.showNetworkFailureToast() + } + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift index 75a4b26e..e5941979 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift @@ -14,7 +14,6 @@ import Moya class CourseUploadVC: UIViewController { // MARK: - Properties -// private var runningModel: RunningModel? private let PublicCourseProvider = Providers.publicCourseProvider private var courseModel: Course? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift index aaa53aa9..283ec60c 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift @@ -127,7 +127,6 @@ extension UploadedCourseInfoVC: UICollectionViewDelegateFlowLayout { courseDetailVC.setCourseId(courseId: courseModel.courseId, publicCourseId: courseModel.id) courseDetailVC.hidesBottomBarWhenPushed = true self.navigationController?.pushViewController(courseDetailVC, animated: true) - } } From 866718259478c82e21eab9c2cdea2662f8cf9f4d Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 17:26:26 +0900 Subject: [PATCH 10/11] =?UTF-8?q?[Feat]=20#125=20-=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Network/Router/CourseRouter.swift | 7 +++ .../CourseDetail/VC/CourseDetailVC.swift | 62 +++++++++---------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift index ca17dfe5..3153a5b7 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift @@ -14,6 +14,7 @@ enum CourseRouter { case getAllPrivateCourse case getPrivateCourseNotUploaded case getCourseDetail(courseId: Int) + case deleteCourse(courseIdList: [Int]) } extension CourseRouter: TargetType { @@ -35,6 +36,8 @@ extension CourseRouter: TargetType { return "/course/private/user" case .getCourseDetail(let courseId): return "/course/detail/\(courseId)" + case .deleteCourse: + return "/course" } } @@ -44,6 +47,8 @@ extension CourseRouter: TargetType { return .post case .getAllPrivateCourse, .getPrivateCourseNotUploaded, .getCourseDetail: return .get + case .deleteCourse: + return .put } } @@ -81,6 +86,8 @@ extension CourseRouter: TargetType { } return .uploadMultipart(multipartFormData) + case .deleteCourse(let courseIdList): + return .requestParameters(parameters: ["courseIdList": courseIdList], encoding: JSONEncoding.default) case .getAllPrivateCourse, .getPrivateCourseNotUploaded, .getCourseDetail: return .requestPlain } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index abbac2ca..86b9ef9b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -141,14 +141,15 @@ extension CourseDetailVC { let editAction = UIAlertAction(title: "수정하기", style: .default, handler: {(_: UIAlertAction!) in self.navigationController?.pushViewController(courseEditVC, animated: false) }) - let delateVC = RNAlertVC(description: "코스를 정말로 삭제하시겠어요?") - delateVC.rightButtonTapAction = { [weak self] in -// self?.delateCourse() + let deleteVC = RNAlertVC(description: "코스를 정말로 삭제하시겠어요?") + deleteVC.rightButtonTapAction = { [weak self] in + deleteVC.dismiss(animated: false) + self?.deleteCourse() } - delateVC.modalPresentationStyle = .overFullScreen - let delateAction = UIAlertAction(title: "삭제하기", style: .destructive, handler: {(_: UIAlertAction!) in - self.present(delateVC, animated: true, completion: nil)}) - [ editAction, delateAction, cancelAction].forEach { editAlertController.addAction($0) } + deleteVC.modalPresentationStyle = .overFullScreen + let deleteAction = UIAlertAction(title: "삭제하기", style: .destructive, handler: {(_: UIAlertAction!) in + self.present(deleteVC, animated: false, completion: nil)}) + [ editAction, deleteAction, cancelAction].forEach { editAlertController.addAction($0) } present(editAlertController, animated: false, completion: nil) } else { // 신고폼 올라오는 거(유저아이디가 내가 아닌 경우) @@ -423,30 +424,27 @@ extension CourseDetailVC { } extension CourseDetailVC { - private func delateCourse() { - // guard let courseId = courseModel?.id else { return } - // let requsetDto = CourseUploadingRequestDto(courseId: courseId, title: titletext, description: descriptiontext) - // - // LoadingIndicator.showLoading() - // PublicCourseProvider.request(.courseUploadingData(param: requsetDto)) { [weak self] response in - // LoadingIndicator.hideLoading() - // guard let self = self else { return } - // switch response { - // case .success(let result): - // let status = result.statusCode - // if 200..<300 ~= status { - // self.navigationController?.popToRootViewController(animated: true) - // } - // if status >= 400 { - // print("400 error") - // self.showNetworkFailureToast() - // } - // case .failure(let error): - // print(error.localizedDescription) - // self.showNetworkFailureToast() - // } - // } - // } - // } + private func deleteCourse() { + guard let courseId = self.courseId else { return } + LoadingIndicator.showLoading() + courseProvider.request(.deleteCourse(courseIdList: [courseId])) { [weak self] response in + LoadingIndicator.hideLoading() + guard let self = self else { return } + switch response { + case .success(let result): + print("리절트", result) + let status = result.statusCode + if 200..<300 ~= status { + print("삭제 성공") + } + if status >= 400 { + print("400 error") + self.showNetworkFailureToast() + } + case .failure(let error): + print(error.localizedDescription) + self.showNetworkFailureToast() + } + } } } From 375e1193c734f146e0ac86d4880b73e505faa7bd Mon Sep 17 00:00:00 2001 From: yeonwoo Date: Sat, 6 May 2023 19:30:48 +0900 Subject: [PATCH 11/11] =?UTF-8?q?[Feat]=20#125=20-=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=EB=B0=94=EB=88=84=EB=A5=B4=EB=A9=B4=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=EC=95=88=EB=90=98=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/CourseDetail/VC/CourseDetailVC.swift | 2 +- .../Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift | 2 +- .../Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 86b9ef9b..2a6d0294 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -198,7 +198,7 @@ extension CourseDetailVC { self.uploadedCourseDetailModel = model self.mapImageView.setImage(with: model.publicCourse.image) self.profileImageView.image = GoalRewardInfoModel.stampNameImageDictionary[model.user.image] - self.profileNameLabel.text = model.user.nickname //유저닉네임 + self.profileNameLabel.text = model.user.nickname self.runningLevelLabel.text = "Lv. \(model.user.level)" self.courseTitleLabel.text = model.publicCourse.title self.isMyCourse = model.user.isNowUser diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift index 0396329a..31e14614 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift @@ -143,7 +143,7 @@ extension CourseEditVC { self.courseTitleTextField.text = String(newString) } - if !text.isEmpty && activityTextView.text != self.placeholder { + if text.count == 0 && activityTextView.text != self.placeholder && activityTextView.text.count == 0 { editButton.setEnabled(true) } else { editButton.setEnabled(false) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift index e5941979..ab274d81 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift @@ -141,7 +141,7 @@ extension CourseUploadVC { self.courseTitleTextField.text = String(newString) } - if !text.isEmpty && activityTextView.text != self.placeholder { + if text.count == 0 && activityTextView.text != self.placeholder && activityTextView.text.count == 0 { uploadButton.setEnabled(true) } else { uploadButton.setEnabled(false)