From 2af95bbe2edd11268017b31e2a4d5f0cf1d6202e Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 15 Mar 2024 15:03:12 +0900 Subject: [PATCH 01/22] =?UTF-8?q?[Feat]=20#244=20-=20mypage=20manager=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 --- .../iOS-NOTTODO.xcodeproj/project.pbxproj | 180 ++++++++++++------ .../Coordinator/MypageCoordinatorImpl.swift | 2 +- .../Factory/ViewControllerFactory.swift | 12 +- .../ManagerInterface/MyPageManger.swift | 14 ++ .../Network/Manager/MyPageManagerImpl.swift | 29 +++ 5 files changed, 171 insertions(+), 66 deletions(-) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj index def00343..9c900043 100644 --- a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj +++ b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj @@ -30,6 +30,21 @@ 0960C0D42A38BC6500A3D8DB /* KeychainUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960C0D32A38BC6500A3D8DB /* KeychainUtil.swift */; }; 0960C0D62A38BC8100A3D8DB /* DefaultKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960C0D52A38BC8100A3D8DB /* DefaultKeys.swift */; }; 0964BA4A2B0F6BFB00A8984B /* AuthInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0964BA492B0F6BFB00A8984B /* AuthInterceptor.swift */; }; + 096980712BA40FCB00D101B9 /* MyPageAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980702BA40FCB00D101B9 /* MyPageAccountModel.swift */; }; + 0969809C2BA4198500D101B9 /* MyInfoAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */; }; + 096980A32BA41A6000D101B9 /* MyPageAccountViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88F12BA3F7A800FE01D4 /* MyPageAccountViewModelImpl.swift */; }; + 096980AA2BA41AB000D101B9 /* MyPageViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980A92BA41AB000D101B9 /* MyPageViewModelImpl.swift */; }; + 096980AC2BA41AC100D101B9 /* MyPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980AB2BA41AC100D101B9 /* MyPageViewModel.swift */; }; + 096980AE2BA41ACC00D101B9 /* MyPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980AD2BA41ACC00D101B9 /* MyPageModel.swift */; }; + 096980B22BA41AF600D101B9 /* MyPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B12BA41AF600D101B9 /* MyPageViewController.swift */; }; + 096980B42BA41B1200D101B9 /* InfoCollecitonViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */; }; + 096980B62BA41B2000D101B9 /* MyPageHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */; }; + 096980B82BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B72BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift */; }; + 096C88EB2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */; }; + 096C88ED2BA3E6B700FE01D4 /* MyInfoAccountSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */; }; + 096C88EF2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EE2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift */; }; + 096C88F42BA3F89D00FE01D4 /* MyPageManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88F32BA3F89D00FE01D4 /* MyPageManger.swift */; }; + 096C88F62BA3F8A600FE01D4 /* MyPageManagerImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88F52BA3F8A600FE01D4 /* MyPageManagerImpl.swift */; }; 097568362A2FEF630001EC46 /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097568352A2FEF3F0001EC46 /* String+.swift */; }; 097C003629AB8270008CAEF3 /* MissionListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097C003529AB8270008CAEF3 /* MissionListCollectionViewCell.swift */; }; 0982DE5429ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982DE5329ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift */; }; @@ -54,10 +69,6 @@ 098904542B81CA47004AAD3C /* UpdateCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098904532B81CA47004AAD3C /* UpdateCoordinator.swift */; }; 098A23A22B833C6700265955 /* AuthCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098A23A12B833C6700265955 /* AuthCoordinator.swift */; }; 098A23A42B833F0300265955 /* AuthCoordinatorImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098A23A32B833F0300265955 /* AuthCoordinatorImpl.swift */; }; - 098BFD5929B7999E008E80F9 /* MyProfileCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098BFD5829B7999E008E80F9 /* MyProfileCollectionViewCell.swift */; }; - 098BFD5B29B79B6A008E80F9 /* MyInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098BFD5A29B79B6A008E80F9 /* MyInfoModel.swift */; }; - 098BFD5D29B79CE3008E80F9 /* InfoCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098BFD5C29B79CE3008E80F9 /* InfoCollectionViewCell.swift */; }; - 098BFD5F29B7AECF008E80F9 /* MyInfoHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098BFD5E29B7AECF008E80F9 /* MyInfoHeaderView.swift */; }; 099FC98129B3094F005B37E6 /* WeekMonthFSCalendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099FC98029B3094F005B37E6 /* WeekMonthFSCalendar.swift */; }; 099FC98329B30A2E005B37E6 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099FC98229B30A2E005B37E6 /* Utils.swift */; }; 099FC98929B3233D005B37E6 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099FC98829B3233D005B37E6 /* CalendarView.swift */; }; @@ -105,7 +116,6 @@ 3B027A9E299C34DA00BEB65C /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027A9D299C34DA00BEB65C /* HomeViewController.swift */; }; 3B027AA0299C353700BEB65C /* AddMissionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027A9F299C353700BEB65C /* AddMissionViewController.swift */; }; 3B027AA2299C355800BEB65C /* AchievementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027AA1299C355800BEB65C /* AchievementViewController.swift */; }; - 3B027AA4299C357000BEB65C /* MyInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027AA3299C357000BEB65C /* MyInfoViewController.swift */; }; 3B027AAC299C35E500BEB65C /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B027AAB299C35E500BEB65C /* Colors.xcassets */; }; 3B03D0D62B0F15AA00302872 /* NotificationDialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03D0D52B0F15AA00302872 /* NotificationDialogViewController.swift */; }; 3B03D0D82B0F5EF300302872 /* CGSize+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03D0D72B0F5EF300302872 /* CGSize+.swift */; }; @@ -157,9 +167,7 @@ 3BEEBE972A4B048A0081C936 /* NottodoToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEEBE962A4B048A0081C936 /* NottodoToastView.swift */; }; 6C049A312A595C670085E40B /* logo.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 6C049A302A595C670085E40B /* logo.mp4 */; }; 6C16015829C40112005AE3F5 /* AuthButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015729C40112005AE3F5 /* AuthButtonView.swift */; }; - 6C16015C29C56DBA005AE3F5 /* MyInfoAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */; }; 6C16016229C59EFD005AE3F5 /* MyInfoAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */; }; - 6C16016429C5E37D005AE3F5 /* MyInfoAccountStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16016329C5E37D005AE3F5 /* MyInfoAccountStackView.swift */; }; 6C44127129A35A1000313C3F /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127029A35A1000313C3F /* KakaoSDK */; }; 6C44127329A35A1000313C3F /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127229A35A1000313C3F /* KakaoSDKAuth */; }; 6C44127529A35A1000313C3F /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127429A35A1000313C3F /* KakaoSDKCommon */; }; @@ -219,6 +227,21 @@ 0960C0D32A38BC6500A3D8DB /* KeychainUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainUtil.swift; sourceTree = ""; }; 0960C0D52A38BC8100A3D8DB /* DefaultKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultKeys.swift; sourceTree = ""; }; 0964BA492B0F6BFB00A8984B /* AuthInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthInterceptor.swift; sourceTree = ""; }; + 096980702BA40FCB00D101B9 /* MyPageAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAccountModel.swift; sourceTree = ""; }; + 096980A92BA41AB000D101B9 /* MyPageViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewModelImpl.swift; sourceTree = ""; }; + 096980AB2BA41AC100D101B9 /* MyPageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewModel.swift; sourceTree = ""; }; + 096980AD2BA41ACC00D101B9 /* MyPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageModel.swift; sourceTree = ""; }; + 096980AF2BA41ADF00D101B9 /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; + 096980B12BA41AF600D101B9 /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; + 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoCollecitonViewCell.swift; sourceTree = ""; }; + 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageHeaderView.swift; sourceTree = ""; }; + 096980B72BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyProfileCollectionViewCell.swift; sourceTree = ""; }; + 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountCollectionViewCell.swift; sourceTree = ""; }; + 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountSection.swift; sourceTree = ""; }; + 096C88EE2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountViewModel.swift; sourceTree = ""; }; + 096C88F12BA3F7A800FE01D4 /* MyPageAccountViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAccountViewModelImpl.swift; sourceTree = ""; }; + 096C88F32BA3F89D00FE01D4 /* MyPageManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageManger.swift; sourceTree = ""; }; + 096C88F52BA3F8A600FE01D4 /* MyPageManagerImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageManagerImpl.swift; sourceTree = ""; }; 097568352A2FEF3F0001EC46 /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; 097C003529AB8270008CAEF3 /* MissionListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionListCollectionViewCell.swift; sourceTree = ""; }; 0982DE5329ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeEmptyCollectionViewCell.swift; sourceTree = ""; }; @@ -243,10 +266,6 @@ 098904532B81CA47004AAD3C /* UpdateCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCoordinator.swift; sourceTree = ""; }; 098A23A12B833C6700265955 /* AuthCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthCoordinator.swift; sourceTree = ""; }; 098A23A32B833F0300265955 /* AuthCoordinatorImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthCoordinatorImpl.swift; sourceTree = ""; }; - 098BFD5829B7999E008E80F9 /* MyProfileCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyProfileCollectionViewCell.swift; sourceTree = ""; }; - 098BFD5A29B79B6A008E80F9 /* MyInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoModel.swift; sourceTree = ""; }; - 098BFD5C29B79CE3008E80F9 /* InfoCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoCollectionViewCell.swift; sourceTree = ""; }; - 098BFD5E29B7AECF008E80F9 /* MyInfoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoHeaderView.swift; sourceTree = ""; }; 099FC98029B3094F005B37E6 /* WeekMonthFSCalendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekMonthFSCalendar.swift; sourceTree = ""; }; 099FC98229B30A2E005B37E6 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 099FC98829B3233D005B37E6 /* CalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarView.swift; sourceTree = ""; }; @@ -294,7 +313,6 @@ 3B027A9D299C34DA00BEB65C /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 3B027A9F299C353700BEB65C /* AddMissionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMissionViewController.swift; sourceTree = ""; }; 3B027AA1299C355800BEB65C /* AchievementViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchievementViewController.swift; sourceTree = ""; }; - 3B027AA3299C357000BEB65C /* MyInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoViewController.swift; sourceTree = ""; }; 3B027AAB299C35E500BEB65C /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; 3B03D0D52B0F15AA00302872 /* NotificationDialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDialogViewController.swift; sourceTree = ""; }; 3B03D0D72B0F5EF300302872 /* CGSize+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGSize+.swift"; sourceTree = ""; }; @@ -345,7 +363,6 @@ 6C16015729C40112005AE3F5 /* AuthButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthButtonView.swift; sourceTree = ""; }; 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountViewController.swift; sourceTree = ""; }; 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountModel.swift; sourceTree = ""; }; - 6C16016329C5E37D005AE3F5 /* MyInfoAccountStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountStackView.swift; sourceTree = ""; }; 6C9628A82A22209E003ADE25 /* LogoOnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoOnboardingViewController.swift; sourceTree = ""; }; 6CA208222A18FE78001C4247 /* RecommendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendService.swift; sourceTree = ""; }; 6CA208242A18FEEA001C4247 /* RecommendAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAPI.swift; sourceTree = ""; }; @@ -503,6 +520,69 @@ path = ViewModel; sourceTree = ""; }; + 0969806F2BA40FBF00D101B9 /* Model */ = { + isa = PBXGroup; + children = ( + 096980702BA40FCB00D101B9 /* MyPageAccountModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + 096980A42BA41A8A00D101B9 /* MyPage */ = { + isa = PBXGroup; + children = ( + 096980A82BA41AA100D101B9 /* Cells */, + 096980A72BA41A9B00D101B9 /* ViewControllers */, + 096980A62BA41A9700D101B9 /* ViewModel */, + 096980A52BA41A9000D101B9 /* Model */, + ); + path = MyPage; + sourceTree = ""; + }; + 096980A52BA41A9000D101B9 /* Model */ = { + isa = PBXGroup; + children = ( + 096980AD2BA41ACC00D101B9 /* MyPageModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + 096980A62BA41A9700D101B9 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 096980A92BA41AB000D101B9 /* MyPageViewModelImpl.swift */, + 096980AB2BA41AC100D101B9 /* MyPageViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 096980A72BA41A9B00D101B9 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + 096980B12BA41AF600D101B9 /* MyPageViewController.swift */, + ); + path = ViewControllers; + sourceTree = ""; + }; + 096980A82BA41AA100D101B9 /* Cells */ = { + isa = PBXGroup; + children = ( + 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */, + 096980B72BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift */, + 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */, + ); + path = Cells; + sourceTree = ""; + }; + 096C88F02BA3F79A00FE01D4 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 096C88EE2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift */, + 096C88F12BA3F7A800FE01D4 /* MyPageAccountViewModelImpl.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 0987C83E2B9DD234007EE8DE /* Mission */ = { isa = PBXGroup; children = ( @@ -575,32 +655,6 @@ path = Factory; sourceTree = ""; }; - 098BFD6029B80137008E80F9 /* Cell */ = { - isa = PBXGroup; - children = ( - 098BFD5E29B7AECF008E80F9 /* MyInfoHeaderView.swift */, - 098BFD5829B7999E008E80F9 /* MyProfileCollectionViewCell.swift */, - 098BFD5C29B79CE3008E80F9 /* InfoCollectionViewCell.swift */, - ); - path = Cell; - sourceTree = ""; - }; - 098BFD6129B80149008E80F9 /* Model */ = { - isa = PBXGroup; - children = ( - 098BFD5A29B79B6A008E80F9 /* MyInfoModel.swift */, - ); - path = Model; - sourceTree = ""; - }; - 098BFD6229B8015B008E80F9 /* Viewcontrollers */ = { - isa = PBXGroup; - children = ( - 3B027AA3299C357000BEB65C /* MyInfoViewController.swift */, - ); - path = Viewcontrollers; - sourceTree = ""; - }; 099CFA1729AB8C260003E5D5 /* ViewControllers */ = { isa = PBXGroup; children = ( @@ -609,6 +663,7 @@ 092C09B42A484DD900E9B06B /* HomeDeleteViewController.swift */, 0930DE6129B80550007958DE /* MissionDetailViewController.swift */, 09582B4E29BEBAFA00EF3207 /* DetailCalendarViewController.swift */, + 096980AF2BA41ADF00D101B9 /* MyPageViewController.swift */, ); path = ViewControllers; sourceTree = ""; @@ -656,6 +711,7 @@ children = ( 09DCB85C2BA0316A00B6BB74 /* ManagerInterface */, 09DCB8612BA031F600B6BB74 /* AchieveManagerImpl.swift */, + 096C88F52BA3F8A600FE01D4 /* MyPageManagerImpl.swift */, ); path = Manager; sourceTree = ""; @@ -664,6 +720,7 @@ isa = PBXGroup; children = ( 09DCB85F2BA031E000B6BB74 /* AchieveManager.swift */, + 096C88F32BA3F89D00FE01D4 /* MyPageManger.swift */, ); path = ManagerInterface; sourceTree = ""; @@ -880,8 +937,8 @@ 3B027A98299C347400BEB65C /* Auth */, 6CF4707729A7AAD1008D145C /* Common */, 3B027A99299C347A00BEB65C /* Home */, - 3B027A9A299C348200BEB65C /* MyInfo */, - 6C16015929C56CE8005AE3F5 /* MyInfoAccount */, + 096980A42BA41A8A00D101B9 /* MyPage */, + 6C16015929C56CE8005AE3F5 /* MyPageAccount */, 6CF4706B29A737E8008D145C /* Recommend */, 6CD4F8B529AA48D900CCC740 /* RecommendAction */, 3B027AA5299C358300BEB65C /* TabBar */, @@ -907,16 +964,6 @@ path = Home; sourceTree = ""; }; - 3B027A9A299C348200BEB65C /* MyInfo */ = { - isa = PBXGroup; - children = ( - 098BFD6229B8015B008E80F9 /* Viewcontrollers */, - 098BFD6029B80137008E80F9 /* Cell */, - 098BFD6129B80149008E80F9 /* Model */, - ); - path = MyInfo; - sourceTree = ""; - }; 3B027A9B299C348800BEB65C /* Achievement */ = { isa = PBXGroup; children = ( @@ -1169,20 +1216,22 @@ path = Toast; sourceTree = ""; }; - 6C16015929C56CE8005AE3F5 /* MyInfoAccount */ = { + 6C16015929C56CE8005AE3F5 /* MyPageAccount */ = { isa = PBXGroup; children = ( + 0969806F2BA40FBF00D101B9 /* Model */, + 096C88F02BA3F79A00FE01D4 /* ViewModel */, 6C16016029C59EE0005AE3F5 /* Models */, 6C16015A29C56D90005AE3F5 /* ViewControllers */, ); - path = MyInfoAccount; + path = MyPageAccount; sourceTree = ""; }; 6C16015A29C56D90005AE3F5 /* ViewControllers */ = { isa = PBXGroup; children = ( 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */, - 6C16016329C5E37D005AE3F5 /* MyInfoAccountStackView.swift */, + 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */, ); path = ViewControllers; sourceTree = ""; @@ -1191,6 +1240,7 @@ isa = PBXGroup; children = ( 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */, + 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */, ); path = Models; sourceTree = ""; @@ -1436,6 +1486,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0969809C2BA4198500D101B9 /* MyInfoAccountViewController.swift in Sources */, 3B03D0D62B0F15AA00302872 /* NotificationDialogViewController.swift in Sources */, 09F6719729CC81B500708725 /* DetailAchievementCollectionViewCell.swift in Sources */, 0960C0D62A38BC8100A3D8DB /* DefaultKeys.swift in Sources */, @@ -1447,7 +1498,6 @@ 6C16016229C59EFD005AE3F5 /* MyInfoAccountModel.swift in Sources */, 3B027A92299C33FE00BEB65C /* UIColor+.swift in Sources */, 092C09B52A484DD900E9B06B /* HomeDeleteViewController.swift in Sources */, - 3B027AA4299C357000BEB65C /* MyInfoViewController.swift in Sources */, 0989043B2B81BCFA004AAD3C /* AppCoordinatorImpl.swift in Sources */, 097568362A2FEF630001EC46 /* String+.swift in Sources */, 6CA2B7BB2A222D2300A9E549 /* ValueOnboardingViewController.swift in Sources */, @@ -1460,15 +1510,14 @@ 095FEE122B9ED15600FF44C0 /* DetailAchieveHeaderView.swift in Sources */, 3B482FA3299EA9CB00BCF424 /* TabBarItem.swift in Sources */, 3B027AA0299C353700BEB65C /* AddMissionViewController.swift in Sources */, - 098BFD5929B7999E008E80F9 /* MyProfileCollectionViewCell.swift in Sources */, 09DCB84D2BA0146800B6BB74 /* DetailAchievementViewModel.swift in Sources */, 3B5F8F7A29BF8E8D0063A7F8 /* AddMissionProtocol.swift in Sources */, 09DCB8512BA0156400B6BB74 /* DetailAchievementViewModelImpl.swift in Sources */, 09F6718C29CB4AB700708725 /* SubOnboardingCollectionViewCell.swift in Sources */, 0921611D2A57D0920019CC8C /* AmplitudeAnalyticsService.swift in Sources */, + 096980712BA40FCB00D101B9 /* MyPageAccountModel.swift in Sources */, 3B027A96299C340C00BEB65C /* UIImage+.swift in Sources */, 0921611F2A57D7BF0019CC8C /* AnalyticsEvent.swift in Sources */, - 098BFD5B29B79B6A008E80F9 /* MyInfoModel.swift in Sources */, 09DCCD1F2A18ED76003DCF8A /* DailyMissionResponseDTO.swift in Sources */, 6CF4707A29A7AAFF008D145C /* PaddingLabel.swift in Sources */, 6CA208272A18FFCF001C4247 /* RecommendResponseDTO.swift in Sources */, @@ -1477,6 +1526,7 @@ 3B50CB212A40E75400F2E761 /* AddMissionResponseDTO.swift in Sources */, 3B37AE2929C8821600AB7587 /* GoalCollectionViewCell.swift in Sources */, 098904322B81BB43004AAD3C /* CoordinatorDelegate.swift in Sources */, + 096980A32BA41A6000D101B9 /* MyPageAccountViewModelImpl.swift in Sources */, 3B14A14329A6FEE400F92897 /* UITextField+.swift in Sources */, 098904482B81C197004AAD3C /* AchieveCoordinator.swift in Sources */, 09022D4629C44BC300DE6E49 /* MissionCalendarCell.swift in Sources */, @@ -1500,10 +1550,10 @@ 3B892ABB2A2FBD4C00A316BC /* RecommendSituationResponseDTO.swift in Sources */, 3B14A13B29A694C000F92897 /* UITextView+.swift in Sources */, 093DB0372A146BF900ECA5F6 /* MyInfoURL.swift in Sources */, - 098BFD5F29B7AECF008E80F9 /* MyInfoHeaderView.swift in Sources */, 09A8E48E2B9DBEC700C0F48F /* BaseService.swift in Sources */, 3B482FA7299EB8FD00BCF424 /* UIViewController+.swift in Sources */, 0960C0D42A38BC6500A3D8DB /* KeychainUtil.swift in Sources */, + 096980B42BA41B1200D101B9 /* InfoCollecitonViewCell.swift in Sources */, 3B03D0D82B0F5EF300302872 /* CGSize+.swift in Sources */, 098904502B81C21D004AAD3C /* AchieveCoordinatorImpl.swift in Sources */, 6CA208302A1925EE001C4247 /* RecommendActionResponseDTO.swift in Sources */, @@ -1512,6 +1562,8 @@ 3B11740D2A4B574B0033DDF3 /* CALayer+.swift in Sources */, 155E456D2B62B1A1008628E7 /* UpdateCheckViewController.swift in Sources */, 098904302B81BB3A004AAD3C /* Coordinator.swift in Sources */, + 096980B22BA41AF600D101B9 /* MyPageViewController.swift in Sources */, + 096980B82BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift in Sources */, 3B14A13D29A6FBD300F92897 /* UIView+.swift in Sources */, 09F6719529CBFCD200708725 /* GradientView.swift in Sources */, 09DCB8622BA031F600B6BB74 /* AchieveManagerImpl.swift in Sources */, @@ -1524,6 +1576,8 @@ 09582B4829BDA7F600EF3207 /* DetailStackView.swift in Sources */, 09F6718429CADB1100708725 /* OnboardingModel.swift in Sources */, 095FEE132B9ED15600FF44C0 /* StatisticsView.swift in Sources */, + 096C88F42BA3F89D00FE01D4 /* MyPageManger.swift in Sources */, + 096980AC2BA41AC100D101B9 /* MyPageViewModel.swift in Sources */, 3B027A7A299C31B500BEB65C /* SceneDelegate.swift in Sources */, 0989043E2B81BD50004AAD3C /* CoordinatorFactory.swift in Sources */, 0964BA4A2B0F6BFB00A8984B /* AuthInterceptor.swift in Sources */, @@ -1535,12 +1589,14 @@ 3BC19A9329CA1CA800C02803 /* UICollectionViewCell+.swift in Sources */, 093DB03D2A15FC7800ECA5F6 /* CalendarReponseDTO.swift in Sources */, 098904462B81C191004AAD3C /* MypageCoordinator.swift in Sources */, + 096C88F62BA3F8A600FE01D4 /* MyPageManagerImpl.swift in Sources */, 093DB03D2A15FC7800ECA5F6 /* CalendarReponseDTO.swift in Sources */, 3B0CBA242A461B1C0004F2DB /* RecentMissionResponseDTO.swift in Sources */, 3B5F8F7F29BF900A0063A7F8 /* DateCollectionViewCell.swift in Sources */, 3BC1A27229C9AF310088376B /* MissionHistoryModels.swift in Sources */, 6CD4F8BA29AA493600CCC740 /* RecommendActionHeaderView.swift in Sources */, 0930DE6229B80550007958DE /* MissionDetailViewController.swift in Sources */, + 096C88ED2BA3E6B700FE01D4 /* MyInfoAccountSection.swift in Sources */, 0989044C2B81C210004AAD3C /* HomecoordinatorImpl.swift in Sources */, 3B14A13F29A6FCB300F92897 /* UIStackView+.swift in Sources */, 6CD4F8BC29AA494300CCC740 /* RecommendActionFooterView.swift in Sources */, @@ -1551,14 +1607,13 @@ 6CF4706A29A71D71008D145C /* Strings.swift in Sources */, 6CF4705F29A69025008D145C /* GeneralResponse.swift in Sources */, 097C003629AB8270008CAEF3 /* MissionListCollectionViewCell.swift in Sources */, - 6C16015C29C56DBA005AE3F5 /* MyInfoAccountViewController.swift in Sources */, 09F6718E29CB612B00708725 /* FifthOnboardingViewController.swift in Sources */, 0987C8402B9DD4DC007EE8DE /* MissionAPI.swift in Sources */, 6CD4F8C229AA5AF200CCC740 /* UIButton+.swift in Sources */, 6CA208362A1957CA001C4247 /* AuthService.swift in Sources */, 6CA208362A1957CA001C4247 /* AuthService.swift in Sources */, 099FC98129B3094F005B37E6 /* WeekMonthFSCalendar.swift in Sources */, - 6C16016429C5E37D005AE3F5 /* MyInfoAccountStackView.swift in Sources */, + 096980AE2BA41ACC00D101B9 /* MyPageModel.swift in Sources */, 3B80B5D52B7F304D00697250 /* adjust+.swift in Sources */, 09F6718229CAD86100708725 /* OnboardingCollectionViewCell.swift in Sources */, 6CF4707029A73A15008D145C /* RecommendActionViewController.swift in Sources */, @@ -1566,6 +1621,7 @@ 0982DE5429ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift in Sources */, 09DCB86B2BA0600600B6BB74 /* AchievementViewModelImpl.swift in Sources */, 3BEEBE972A4B048A0081C936 /* NottodoToastView.swift in Sources */, + 096C88EF2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift in Sources */, 3B027AA2299C355800BEB65C /* AchievementViewController.swift in Sources */, 3B5F8F8929BF9EFE0063A7F8 /* AddMissionLabel.swift in Sources */, 09582B4F29BEBAFA00EF3207 /* DetailCalendarViewController.swift in Sources */, @@ -1577,17 +1633,19 @@ 6C9628A92A22209E003ADE25 /* LogoOnboardingViewController.swift in Sources */, 09F6718029CAD76C00708725 /* SecondOnboardingViewController.swift in Sources */, 098A23A42B833F0300265955 /* AuthCoordinatorImpl.swift in Sources */, - 098BFD5D29B79CE3008E80F9 /* InfoCollectionViewCell.swift in Sources */, 3B0CBA222A45FC170004F2DB /* UpdateMissionResponseDTO.swift in Sources */, 092C09B72A48596500E9B06B /* DeleteModalView.swift in Sources */, 155E45692B5FF2EE008628E7 /* FirebaseUtil.swift in Sources */, + 096980B62BA41B2000D101B9 /* MyPageHeaderView.swift in Sources */, 09DCB8562BA0308D00B6BB74 /* APIError.swift in Sources */, 098904402B81BFAF004AAD3C /* ViewControllerFactory.swift in Sources */, 3B9532F42A284CC1006510F8 /* ModalProtocol.swift in Sources */, 3B5F8F8329BF90290063A7F8 /* SituationCollectionViewCell.swift in Sources */, + 096980AA2BA41AB000D101B9 /* MyPageViewModelImpl.swift in Sources */, 3B4E12F62A27C0BE001D1EC1 /* QuitModalView.swift in Sources */, 6CA208232A18FE78001C4247 /* RecommendService.swift in Sources */, 6CA208342A1956ED001C4247 /* AuthAPI.swift in Sources */, + 096C88EB2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift in Sources */, 0921611B2A5727EF0019CC8C /* AnalyticsEventProtocol.swift in Sources */, 09DCB8692BA05F9E00B6BB74 /* AchievementModel.swift in Sources */, 098904542B81CA47004AAD3C /* UpdateCoordinator.swift in Sources */, diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift index 03bb656d..1743b5e8 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift @@ -59,7 +59,7 @@ final class MypageCoordinatorImpl: MypageCoordinator { logoutAlert.addAction(logoutAction) navigationController.present(logoutAlert, animated: true) } - + func connectAuthCoordinator(type: ViewType) { navigationController.dismiss(animated: true) { [weak self] in self?.finish() diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift index e1ebf681..92a3dcff 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift @@ -38,7 +38,7 @@ protocol HomeFlowControllerFactory { } protocol MyPageFlowControllerFactory { - func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyInfoViewController + func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController } @@ -186,13 +186,17 @@ extension ViewControllerFactoryImpl { } // mypage extension ViewControllerFactoryImpl { - func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyInfoViewController { - let viewController = MyInfoViewController(coordinator: coordinator) + func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController { + let viewModel = MyPageViewModelImpl(coordinator: coordinator) + let viewController = MyPageViewController(viewModel: viewModel) return viewController } func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController { - let viewController = MyInfoAccountViewController(coordinator: coordinator) + let authAPI = DefaultAuthService() + let manager = MyPageManagerImpl(authAPI: authAPI) + let viewModel = MyPageAccountViewModelImpl(coordinator: coordinator, manager: manager) + let viewController = MyInfoAccountViewController(viewModel: viewModel) return viewController } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift new file mode 100644 index 00000000..25a2bc24 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift @@ -0,0 +1,14 @@ +// +// MyPageManger.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +protocol MyPageManger { + func logout() -> AnyPublisher + func withdrawl() -> AnyPublisher +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift new file mode 100644 index 00000000..40114097 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift @@ -0,0 +1,29 @@ +// +// MyPageManagerImpl.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +final class MyPageManagerImpl: MyPageManger { + + private let authAPI: AuthServiceProtocol + private let cancelBag = Set() + + init(authAPI: AuthServiceProtocol) { + self.authAPI = authAPI + } + + func logout() -> AnyPublisher { + authAPI.logout() + .eraseToAnyPublisher() + } + + func withdrawl() -> AnyPublisher { + authAPI.withdrawal() + .eraseToAnyPublisher() + } +} From b81b1be3cbd23b6743dd7fd4fe694c464a851a3a Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 15 Mar 2024 15:04:45 +0900 Subject: [PATCH 02/22] =?UTF-8?q?[Feat]=20#244=20-=20mypage=20account=20MV?= =?UTF-8?q?VM=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Network/Service/Auth/AuthService.swift | 18 ++ .../MyInfo/Model/MyInfoModel.swift | 30 --- .../MyInfoAccountViewController.swift | 204 ----------------- .../Model/MyPageAccountModel.swift | 36 +++ .../Models/MyInfoAccountModel.swift | 0 .../Models/MyInfoAccountSection.swift | 13 ++ .../MyInfoAccountCollectionViewCell.swift} | 112 ++++------ .../MyInfoAccountViewController.swift | 211 ++++++++++++++++++ .../ViewModel/MyInfoAccountViewModel.swift | 24 ++ .../MyPageAccountViewModelImpl.swift | 100 +++++++++ 10 files changed, 451 insertions(+), 297 deletions(-) delete mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Model/MyInfoModel.swift delete mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountViewController.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfoAccount => MyPageAccount}/Models/MyInfoAccountModel.swift (100%) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfoAccount/ViewControllers/MyInfoAccountStackView.swift => MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift} (56%) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Service/Auth/AuthService.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Service/Auth/AuthService.swift index e4b22393..ce36c55f 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Network/Service/Auth/AuthService.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Service/Auth/AuthService.swift @@ -6,9 +6,27 @@ // import Foundation +import Combine import Moya +protocol AuthServiceProtocol { + func logout() -> AnyPublisher + func withdrawal() -> AnyPublisher +} + +typealias DefaultAuthService = BaseService + +extension DefaultAuthService: AuthServiceProtocol { + func logout() -> AnyPublisher { + return requestWithCombineNoResult(AuthAPI.logout) + } + + func withdrawal() -> AnyPublisher { + return requestWithCombineNoResult(AuthAPI.withdrawal) + } +} + typealias AuthData = GeneralResponse typealias EmptyData = GeneralResponse diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Model/MyInfoModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Model/MyInfoModel.swift deleted file mode 100644 index 68c5f2f7..00000000 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Model/MyInfoModel.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// MyInfoModel.swift -// iOS-NOTTODO -// -// Created by JEONGEUN KIM on 2023/03/08. -// - -import UIKit - -struct InfoModel: Hashable { - - var image: UIImage? - var user: String? - var email: String? - var title: String? - - static var profile: [InfoModel] = [InfoModel(image: .imgUser, - user: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname(), - email: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail())] - - static let support: [InfoModel] = [InfoModel(image: .icGuide, title: I18N.guide), - InfoModel(image: .icQuestion1, title: I18N.oftenQuestion) - ] - static let info: [InfoModel] = [InfoModel(title: I18N.notice), - InfoModel(title: I18N.sendFeedback), - InfoModel(title: I18N.inquiry), - InfoModel(title: I18N.policies) - ] - static func version() -> [InfoModel] { return [InfoModel(title: I18N.version + " " + (Utils.version ?? "1.0.0"))] } -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountViewController.swift deleted file mode 100644 index 6eeb0588..00000000 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountViewController.swift +++ /dev/null @@ -1,204 +0,0 @@ -// -// MyInfoAccountViewController.swift -// iOS-NOTTODO -// -// Created by 김민서 on 2023/03/18. -// - -import UIKit - -import KakaoSDKUser - -final class MyInfoAccountViewController: UIViewController { - - // MARK: - Property - - private weak var coordinator: MypageCoordinator? - - // MARK: - UI Components - - private let navigationView = UIView() - private let backButton = UIButton() - private let navigationTitle = UILabel() - private let seperateView = UIView() - - private let verticalStackView = UIStackView() - private let nicknameView = MyInfoAccountStackView(title: I18N.nickname, isHidden: false) - private let emailView = MyInfoAccountStackView(title: I18N.email, isHidden: false) - private let accountView = MyInfoAccountStackView(title: I18N.account, isHidden: false) - private let notificationView = MyInfoAccountStackView(title: I18N.notification, isHidden: true) - - private let logoutView = UIView() - private let logoutButton = UIButton() - private let withdrawButton = UIButton() - - // MARK: - init - - init(coordinator: MypageCoordinator) { - self.coordinator = coordinator - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Life Cycle - - override func viewDidLoad() { - super.viewDidLoad() - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.viewAccountInfo) - setUI() - setLayout() - configure(model: MyInfoAccountModel(nickname: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname(), email: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail(), account: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? "apple" : "kakao", notification: true)) - } -} - -// MARK: - Methods - -private extension MyInfoAccountViewController { - func setUI() { - self.notificationView.switchClosure = { [weak self] result in - self?.notificationView.notificationSwitch.setOn(result, animated: true) - } - - view.backgroundColor = .ntdBlack - seperateView.backgroundColor = .gray2 - - backButton.do { - $0.setBackgroundImage(.icBack, for: .normal) - $0.addTarget(self, action: #selector(popBackbutton), for: .touchUpInside) - } - - navigationTitle.do { - $0.font = .Pretendard(.semiBold, size: 18) - $0.textColor = .white - $0.text = I18N.myInfoAccount - } - - verticalStackView.do { - $0.addArrangedSubviews(nicknameView, emailView, accountView, notificationView) - $0.axis = .vertical - $0.spacing = 0 - $0.distribution = .equalSpacing - $0.makeCornerRound(radius: 10) - $0.backgroundColor = .gray1 - } - - logoutView.do { - $0.makeCornerRound(radius: 10) - $0.backgroundColor = .gray1 - } - - logoutButton.do { - $0.setTitle(I18N.logout, for: .normal) - $0.setTitleColor(.ntdRed, for: .normal) - $0.titleLabel?.font = .Pretendard(.medium, size: 14) - $0.addTarget(self, action: #selector(tappedLogout), for: .touchUpInside) - } - - withdrawButton.do { - $0.setTitle(I18N.withdraw, for: .normal) - $0.setTitleColor(.gray4, for: .normal) - $0.titleLabel?.font = .Pretendard(.regular, size: 12) - $0.setUnderline() - $0.addTarget(self, action: #selector(presentToWithdraw), for: .touchUpInside) - } - } - - func setLayout() { - view.addSubviews(navigationView, seperateView, verticalStackView, logoutView, withdrawButton) - navigationView.addSubviews(backButton, navigationTitle) - logoutView.addSubview(logoutButton) - - navigationView.snp.makeConstraints { - $0.top.equalTo(view.safeAreaLayoutGuide) - $0.directionalHorizontalEdges.equalToSuperview() - $0.height.equalTo(58) - } - - backButton.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.leading.equalToSuperview().offset(15) - } - - navigationTitle.snp.makeConstraints { - $0.center.equalToSuperview() - } - - seperateView.snp.makeConstraints { - $0.top.equalTo(navigationView.snp.bottom) - $0.directionalHorizontalEdges.equalToSuperview() - $0.height.equalTo(0.7) - } - - verticalStackView.snp.makeConstraints { - $0.top.equalTo(navigationView.snp.bottom).offset(35) - $0.directionalHorizontalEdges.equalToSuperview().inset(22) - } - - logoutView.snp.makeConstraints { - $0.top.equalTo(verticalStackView.snp.bottom).offset(21) - $0.directionalHorizontalEdges.equalToSuperview().inset(22) - $0.height.equalTo(50) - } - - logoutButton.snp.makeConstraints { - $0.leading.equalToSuperview().offset(20) - $0.centerY.equalToSuperview() - } - - withdrawButton.snp.makeConstraints { - $0.centerX.equalToSuperview() - $0.bottom.equalToSuperview().offset(-119) - } - } - - func configure(model: MyInfoAccountModel) { - nicknameView.contentLabel.text = model.nickname - emailView.contentLabel.text = model.email - accountView.contentLabel.text = model.account - } - - @objc - private func presentToWithdraw() { - coordinator?.showWithdrawViewController() - } - @objc - private func tappedLogout() { - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearLogoutModal) - coordinator?.showLogoutAlertController { [weak self] in - self?.logout() - } - } - - @objc - private func popBackbutton() { - coordinator?.popViewController() - } -} - -extension MyInfoAccountViewController { - func logout() { - if !KeychainUtil.getBool(DefaultKeys.isAppleLogin) { - kakaoLogout() - } - - AuthService.shared.deleteAuth { [weak self] _ in - guard let self else { return } - self.coordinator?.connectAuthCoordinator(type: .logout ) - - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeLogout) - } - } - - func kakaoLogout() { - UserApi.shared.logout {(error) in - if let error = error { - print(error) - } else { - print("logout() success.") - } - } - } -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift new file mode 100644 index 00000000..df33f851 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift @@ -0,0 +1,36 @@ +// +// MyPageAccountModel.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import UIKit + +struct MyPageAccountModel: Equatable { + let profileData: [AccountRowData] + let logout: [AccountRowData] +} + +struct AccountRowData: Hashable { + var title: String + var content: String? + var titleColor: UIColor = .white + var isSwitch: Bool = false + + static func userInfo() -> [AccountRowData] { + return [AccountRowData(title: I18N.nickname, + content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname()), + AccountRowData(title: I18N.email, + content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail()), + AccountRowData(title: I18N.account, + content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? "apple" : "kakao"), + AccountRowData(title: I18N.notification, + isSwitch: true)] + } + + static func logout() -> [AccountRowData] { + return [AccountRowData(title: I18N.logout, + titleColor: .ntdRed!)] + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/Models/MyInfoAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift similarity index 100% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/Models/MyInfoAccountModel.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift new file mode 100644 index 00000000..d6936732 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift @@ -0,0 +1,13 @@ +// +// MyInfoAccountSection.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +// +// +//enum MyInfoSections { +// +//} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountStackView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift similarity index 56% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountStackView.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift index 8a8e8022..5fe3c018 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfoAccount/ViewControllers/MyInfoAccountStackView.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift @@ -1,66 +1,55 @@ // -// MyInfoAccountStackView.swift +// MyInfoAccountCollectionViewCell.swift // iOS-NOTTODO // -// Created by 김민서 on 2023/03/18. +// Created by JEONGEUN KIM on 3/15/24. // import UIKit import SnapKit import Then -import UserNotifications -final class MyInfoAccountStackView: UIView { +final class MyInfoAccountCollectionViewCell: UICollectionViewCell { - // MARK: - UI Components + // MARK: - Properties + + static let identifier = "MyInfoAccountCollectionViewCell" - private let stackView = UIView() - let titleLabel = UILabel() - let contentLabel = UILabel() - let notificationSwitch = UISwitch() - private let lineView = UIView() - var switchClosure: ((_ isTapped: Bool) -> Void)? private var isNotificationAllowed: Bool { return KeychainUtil.getBool(DefaultKeys.isNotificationAccepted) } - // MARK: - View Life Cycle + // MARK: - UI Components + + private let titleLabel = UILabel() + private let contentLabel = UILabel() + private let notificationSwitch = UISwitch() + + // MARK: - init - init(title: String, isHidden: Bool) { + override init(frame: CGRect) { super.init(frame: .zero) - setUI(title: title, isHidden: isHidden) - setLayout(isHidden: isHidden) - NotificationCenter.default.addObserver( - self, - selector: #selector(appWillEnterForeground), - name: UIApplication.willEnterForegroundNotification, - object: nil) + setUI() + setLayout() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - deinit { - NotificationCenter.default.removeObserver( - self, - name: UIApplication.willEnterForegroundNotification, - object: nil) - } } // MARK: - Methods -extension MyInfoAccountStackView { - private func setUI(title: String, isHidden: Bool) { - makeCornerRound(radius: 10) +extension MyInfoAccountCollectionViewCell { + + private func setUI() { + backgroundColor = .gray1 titleLabel.do { - $0.text = title $0.font = .Pretendard(.medium, size: 14) - $0.textColor = .white $0.numberOfLines = 0 $0.textAlignment = .left } @@ -77,50 +66,46 @@ extension MyInfoAccountStackView { $0.onTintColor = .green2 $0.addTarget(self, action: #selector(switchTapped), for: .valueChanged) } - - lineView.do { - $0.backgroundColor = .gray2 - $0.isHidden = isHidden ? true : false - } } - private func setLayout(isHidden: Bool) { - addSubviews(lineView, stackView) - stackView.addSubviews(titleLabel, isHidden ? notificationSwitch : contentLabel) + private func setLayout() { + contentView.addSubviews(titleLabel, contentLabel, notificationSwitch) - stackView.snp.makeConstraints { - $0.top.equalToSuperview().offset(10) - $0.directionalHorizontalEdges.equalToSuperview().inset(20) - $0.bottom.equalToSuperview().inset(10) - $0.height.equalTo(30) + titleLabel.snp.makeConstraints { + $0.leading.equalToSuperview().inset(20) + $0.centerY.equalToSuperview() } - titleLabel.snp.makeConstraints { + contentLabel.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(18) $0.centerY.equalToSuperview() } - if !isHidden { - contentLabel.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.trailing.equalToSuperview() - } - } else { - notificationSwitch.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.trailing.equalToSuperview() - $0.height.equalTo(30) - $0.width.equalTo(50) - } + notificationSwitch.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(18) + $0.centerY.equalToSuperview() + $0.height.equalTo(30) + $0.width.equalTo(50) } + } + + func configure(data: AccountRowData) { + titleLabel.textColor = data.titleColor + titleLabel.text = data.title - lineView.snp.makeConstraints { - $0.directionalHorizontalEdges.equalToSuperview() - $0.bottom.equalToSuperview() - $0.height.equalTo(0.5) + if data.isSwitch { + contentLabel.removeFromSuperview() + } else { + notificationSwitch.removeFromSuperview() + contentLabel.text = data.content } } +} + +extension MyInfoAccountCollectionViewCell { - @objc func switchTapped(_ sender: Any) { + @objc + func switchTapped(_ sender: Any) { DispatchQueue.main.async { do { @@ -160,7 +145,8 @@ extension MyInfoAccountStackView { DispatchQueue.main.async { KeychainUtil.setBool(settings.authorizationStatus == .authorized, forKey: DefaultKeys.isNotificationAccepted) if let isNotificationAllowed = self?.isNotificationAllowed { - self?.switchClosure?(isNotificationAllowed) + + // self?.delegate?.switchTapped(isNotificationAllowed) } if KeychainUtil.getBool(DefaultKeys.isNotificationAccepted) { diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift new file mode 100644 index 00000000..47131045 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift @@ -0,0 +1,211 @@ +// +// MyInfoAccountViewController.swift +// iOS-NOTTODO +// +// Created by 김민서 on 2023/03/18. +// + +import UIKit +import Combine + +final class MyInfoAccountViewController: UIViewController { + + // MARK: - Property + + typealias CellRegistration = UICollectionView.CellRegistration + typealias HeaderRegistration = UICollectionView.SupplementaryRegistration + typealias DataSource = UICollectionViewDiffableDataSource + typealias SnapShot = NSDiffableDataSourceSnapshot + + enum Sections: Int, CaseIterable { + case account, logout + } + + private let viewWillAppearSubject = PassthroughSubject() + private let withdrawalTapped = PassthroughSubject() + private let logoutTapped = PassthroughSubject() + private let backButtonTapped = PassthroughSubject() + private var cancelBag = Set() + + private var dataSource: DataSource? + private var viewModel: any MyPageAccountViewModel + + // MARK: - UI Components + + private lazy var safeArea = self.view.safeAreaLayoutGuide + + private let navigationView = UIView() + private let backButton = UIButton() + private let navigationTitle = UILabel() + private let seperateView = UIView() + private let withdrawButton = UIButton() + private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) + + // MARK: - init + + init(viewModel: some MyPageAccountViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life Cycle + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + viewWillAppearSubject.send(()) + } + + override func viewDidLoad() { + super.viewDidLoad() + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.viewAccountInfo) + + setUI() + setLayout() + setupDataSource() + setBindings() + } +} + +// MARK: - Methods + +private extension MyInfoAccountViewController { + + func setUI() { + view.backgroundColor = .ntdBlack + seperateView.backgroundColor = .gray2 + + backButton.do { + $0.setBackgroundImage(.icBack, for: .normal) + $0.addTarget(self, action: #selector(popBackbutton), for: .touchUpInside) + } + + navigationTitle.do { + $0.font = .Pretendard(.semiBold, size: 18) + $0.textColor = .white + $0.text = I18N.myInfoAccount + } + + collectionView.do { + $0.collectionViewLayout = layout() + $0.backgroundColor = .clear + $0.bounces = false + $0.autoresizingMask = [.flexibleWidth, .flexibleHeight] + $0.showsVerticalScrollIndicator = false + $0.delegate = self + } + + withdrawButton.do { + $0.setTitle(I18N.withdraw, for: .normal) + $0.setTitleColor(.gray4, for: .normal) + $0.titleLabel?.font = .Pretendard(.regular, size: 12) + $0.setUnderline() + $0.addTarget(self, action: #selector(presentToWithdraw), for: .touchUpInside) + } + } + + func setLayout() { + view.addSubviews(navigationView, seperateView, collectionView, withdrawButton) + navigationView.addSubviews(backButton, navigationTitle) + + navigationView.snp.makeConstraints { + $0.top.equalTo(view.safeAreaLayoutGuide) + $0.directionalHorizontalEdges.equalToSuperview() + $0.height.equalTo(58) + } + + backButton.snp.makeConstraints { + $0.centerY.equalToSuperview() + $0.leading.equalToSuperview().offset(15) + } + + navigationTitle.snp.makeConstraints { + $0.center.equalToSuperview() + } + + seperateView.snp.makeConstraints { + $0.top.equalTo(navigationView.snp.bottom) + $0.directionalHorizontalEdges.equalToSuperview() + $0.height.equalTo(0.7) + } + + collectionView.snp.makeConstraints { + $0.top.equalTo(navigationView.snp.bottom).offset(35) + $0.horizontalEdges.equalTo(safeArea).inset(22) + $0.bottom.equalTo(safeArea) + } + + withdrawButton.snp.makeConstraints { + $0.centerX.equalTo(safeArea) + $0.bottom.equalTo(safeArea).inset(119) + } + } + + private func setupDataSource() { + let cellRegistration = CellRegistration {cell, _, item in + cell.configure(data: item) + } + + dataSource = DataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, + for: indexPath, + item: item) + }) + } + + private func setBindings() { + let input = MyPageAccountViewModelInput(viewWillAppearSubject: viewWillAppearSubject, withdrawalTapped: withdrawalTapped, logoutTapped: logoutTapped, backButtonTapped: backButtonTapped) + + let output = viewModel.transform(input: input) + + output.viewWillAppearSubject + .receive(on: RunLoop.main) + .sink { [weak self] in + self?.setSnapShot(userInfo: $0.profileData, logout: $0.logout) + } + .store(in: &cancelBag) + } + + private func setSnapShot(userInfo: [AccountRowData], logout: [AccountRowData]) { + var snapShot = SnapShot() + + snapShot.appendSections(Sections.allCases) + snapShot.appendItems(userInfo, toSection: .account) + snapShot.appendItems(logout, toSection: .logout) + + dataSource?.apply(snapShot, animatingDifferences: false) + } + + private func layout() -> UICollectionViewLayout { + UICollectionViewCompositionalLayout { _, env in + return CompositionalLayout.setUpSection(layoutEnvironment: env, topContentInset: 18) + } + } + + @objc + private func presentToWithdraw() { + withdrawalTapped.send(()) + } + + @objc + private func popBackbutton() { + backButtonTapped.send(()) + } +} + +extension MyInfoAccountViewController: UICollectionViewDelegate { + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let section = Sections(rawValue: indexPath.section) + switch section { + case .logout: + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearLogoutModal) + logoutTapped.send(()) + default: break + } + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift new file mode 100644 index 00000000..bc276a48 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift @@ -0,0 +1,24 @@ +// +// MyInfoAccountViewModel.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +protocol MyPageAccountViewModelPresentable {} + +protocol MyPageAccountViewModel: ViewModel where Input == MyPageAccountViewModelInput, Output == MyPageAccountViewModelOutput {} + +struct MyPageAccountViewModelInput { + let viewWillAppearSubject: PassthroughSubject + let withdrawalTapped: PassthroughSubject + let logoutTapped: PassthroughSubject + let backButtonTapped: PassthroughSubject +} + +struct MyPageAccountViewModelOutput { + let viewWillAppearSubject: AnyPublisher +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift new file mode 100644 index 00000000..799bb66e --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift @@ -0,0 +1,100 @@ +// +// MyInfoAccountViewModelImpl.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +import KakaoSDKUser + +final class MyPageAccountViewModelImpl: MyPageAccountViewModel { + + private weak var coordinator: MypageCoordinator? + private var manager: MyPageManger + private var cancelBag = Set() + + init(coordinator: MypageCoordinator, manager: MyPageManger) { + self.coordinator = coordinator + self.manager = manager + } + + func transform(input: MyPageAccountViewModelInput) -> MyPageAccountViewModelOutput { + + let viewWillAppearSubject = input.viewWillAppearSubject + .map { _ -> MyPageAccountModel in + return MyPageAccountModel(profileData: AccountRowData.userInfo(), logout: AccountRowData.logout()) + } + .eraseToAnyPublisher() + + input.backButtonTapped + .sink(receiveValue: { [weak self] _ in + guard let self else { return } + self.coordinator?.popViewController() + }) + .store(in: &cancelBag) + + input.withdrawalTapped + .sink(receiveValue: { [weak self] _ in + guard let self else { return } + self.coordinator?.showWithdrawViewController() + }) + .store(in: &cancelBag) + + input.logoutTapped + .sink(receiveValue: { [weak self] _ in + guard let self else { return } + self.coordinator?.showLogoutAlertController { + print("Tapped logout ") + } + }) + .store(in: &cancelBag) + + return Output(viewWillAppearSubject: viewWillAppearSubject) + } + + func logout() { + manager.logout() + .sink(receiveCompletion: { event in + print("completion: \(event)") + }, receiveValue: { data in + dump(data) + }) + .store(in: &cancelBag) + } + + func withdrawal() { + manager.withdrawl() + .sink(receiveCompletion: { event in + print("completion: \(event)") + }, receiveValue: { data in + dump(data) + }) + .store(in: &cancelBag) + } + + // func logout() { + // if !KeychainUtil.getBool(DefaultKeys.isAppleLogin) { + // kakaoLogout() + // } + // + // AuthService.shared.deleteAuth { [weak self] _ in + // guard let self else { return } + // self.coordinator?.connectAuthCoordinator(type: .logout ) + // + // AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeLogout) + // } + // } + // + // func kakaoLogout() { + // UserApi.shared.logout {(error) in + // if let error = error { + // print(error) + // } else { + // print("logout() success.") + // } + // } + // } +} From f56cb7a90efc0d69a47b9ede3aaceb07395c2cdc Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 15 Mar 2024 15:05:04 +0900 Subject: [PATCH 03/22] =?UTF-8?q?[Feat]=20#244=20-=20Mypage=20MVVM=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyPageViewController.swift | 8 ++ .../Cells/InfoCollecitonViewCell.swift} | 8 +- .../Cells/MyPageHeaderView.swift} | 8 +- .../Cells}/MyProfileCollectionViewCell.swift | 6 +- .../MyPage/Model/MyPageModel.swift | 53 +++++++++ .../MyPageViewController.swift} | 103 ++++++++++-------- .../MyPage/ViewModel/MyPageViewModel.swift | 22 ++++ .../ViewModel/MyPageViewModelImpl.swift | 40 +++++++ 8 files changed, 192 insertions(+), 56 deletions(-) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfo/Cell/InfoCollectionViewCell.swift => MyPage/Cells/InfoCollecitonViewCell.swift} (92%) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfo/Cell/MyInfoHeaderView.swift => MyPage/Cells/MyPageHeaderView.swift} (84%) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfo/Cell => MyPage/Cells}/MyProfileCollectionViewCell.swift (94%) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift rename iOS-NOTTODO/iOS-NOTTODO/Presentation/{MyInfo/Viewcontrollers/MyInfoViewController.swift => MyPage/ViewControllers/MyPageViewController.swift} (67%) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift new file mode 100644 index 00000000..546396e4 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift @@ -0,0 +1,8 @@ +// +// MyPageViewController.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/InfoCollectionViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift similarity index 92% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/InfoCollectionViewCell.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift index b667cb6d..60aad595 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/InfoCollectionViewCell.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift @@ -1,8 +1,8 @@ // -// InfoCollectionViewCell.swift +// InfoCollecitonViewCell.swift // iOS-NOTTODO // -// Created by JEONGEUN KIM on 2023/03/08. +// Created by JEONGEUN KIM on 3/15/24. // import UIKit @@ -81,7 +81,7 @@ extension InfoCollectionViewCell { } } - func configureWithIcon(with model: InfoModel) { + func configureWithIcon(with model: MyPageRowData) { iconImage.image = model.image titleLabel.text = model.title @@ -91,7 +91,7 @@ extension InfoCollectionViewCell { } } - func configure(with model: InfoModel, isHidden: Bool) { + func configure(with model: MyPageRowData, isHidden: Bool) { horizontalStackView.removeArrangedSubview(iconImage) iconImage.removeFromSuperview() titleLabel.text = model.title diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyInfoHeaderView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyPageHeaderView.swift similarity index 84% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyInfoHeaderView.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyPageHeaderView.swift index aecc8d6d..30035638 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyInfoHeaderView.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyPageHeaderView.swift @@ -1,8 +1,8 @@ // -// MyInfoHeaderCollectionReusableView.swift +// MyPageHeaderView.swift // iOS-NOTTODO // -// Created by JEONGEUN KIM on 2023/03/08. +// Created by JEONGEUN KIM on 3/15/24. // import UIKit @@ -10,7 +10,7 @@ import UIKit import Then import SnapKit -final class MyInfoHeaderView: UICollectionReusableView { +final class MyPageHeaderView: UICollectionReusableView { // MARK: - Properties @@ -36,7 +36,7 @@ final class MyInfoHeaderView: UICollectionReusableView { // MARK: - Methods -extension MyInfoHeaderView { +extension MyPageHeaderView { private func setUI() { myInfoLabel.do { diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyProfileCollectionViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyProfileCollectionViewCell.swift similarity index 94% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyProfileCollectionViewCell.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyProfileCollectionViewCell.swift index 2bdefe65..49a80b41 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Cell/MyProfileCollectionViewCell.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/MyProfileCollectionViewCell.swift @@ -1,8 +1,8 @@ // -// MyInfoCollectionViewCell.swift +// MyProfileCollectionViewCell.swift // iOS-NOTTODO // -// Created by JEONGEUN KIM on 2023/03/08. +// Created by JEONGEUN KIM on 3/15/24. // import UIKit @@ -82,7 +82,7 @@ extension MyProfileCollectionViewCell { } } - func configure(model: InfoModel) { + func configure(model: MyPageRowData) { logoImage.image = model.image userLabel.text = model.user emailLabel.text = model.email diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift new file mode 100644 index 00000000..8b32b08d --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift @@ -0,0 +1,53 @@ +// +// MyPageModel.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import UIKit + +struct MyPageModel: Hashable { + let sections: [Section] + + enum Section: CaseIterable { + case profile, support, info, version + + var rows: [MyPageRowData] { + switch self { + case .profile: + return MyPageRowData.profile + case .support: + return MyPageRowData.support + case .info: + return MyPageRowData.info + case .version: + return MyPageRowData.version() + } + } + } +} + +struct MyPageRowData: Hashable { + + var image: UIImage? + var user: String? + var email: String? + var title: String? + + static var profile: [MyPageRowData] = [MyPageRowData(image: .imgUser, + user: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname(), + email: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail())] + + static let support: [MyPageRowData] = [MyPageRowData(image: .icGuide, title: I18N.guide), + MyPageRowData(image: .icQuestion1, title: I18N.oftenQuestion) + ] + + static let info: [MyPageRowData] = [MyPageRowData(title: I18N.notice), + MyPageRowData(title: I18N.sendFeedback), + MyPageRowData(title: I18N.inquiry), + MyPageRowData(title: I18N.policies) + ] + + static func version() -> [MyPageRowData] { return [MyPageRowData(title: I18N.version + " " + (Utils.version ?? "1.0.0"))] } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Viewcontrollers/MyInfoViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift similarity index 67% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Viewcontrollers/MyInfoViewController.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift index a257c00a..9e6bb589 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyInfo/Viewcontrollers/MyInfoViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift @@ -1,38 +1,45 @@ // -// MyInfoViewController.swift +// MyPageViewController.swift // iOS-NOTTODO // -// Created by 강윤서 on 2023/02/15. +// Created by JEONGEUN KIM on 3/15/24. // import UIKit +import Combine import Then import SnapKit -final class MyInfoViewController: UIViewController { +final class MyPageViewController: UIViewController { // MARK: - Properties typealias CellRegistration = UICollectionView.CellRegistration typealias HeaderRegistration = UICollectionView.SupplementaryRegistration - typealias DataSource = UICollectionViewDiffableDataSource - typealias SnapShot = NSDiffableDataSourceSnapshot + typealias DataSource = UICollectionViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot enum Sections: Int, CaseIterable { case profile, support, info, version } + private let viewWillAppearSubject = PassthroughSubject() + private let profilCellTapped = PassthroughSubject() + private var cancelBag = Set() + private var dataSource: DataSource? + private let viewModel: any MyPageViewModel - private lazy var safeArea = self.view.safeAreaLayoutGuide + // MARK: - UI Components - private weak var coordinator: MypageCoordinator? + private lazy var safeArea = self.view.safeAreaLayoutGuide + private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) // MARK: - init - init(coordinator: MypageCoordinator) { - self.coordinator = coordinator + init(viewModel: some MyPageViewModel) { + self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } @@ -40,12 +47,14 @@ final class MyInfoViewController: UIViewController { fatalError("init(coder:) has not been implemented") } - // MARK: - UI Components - - private let myInfoCollectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) - // MARK: - Life Cycle + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + viewWillAppearSubject.send(()) + } + override func viewDidLoad() { super.viewDidLoad() @@ -53,18 +62,18 @@ final class MyInfoViewController: UIViewController { setUI() setLayout() setupDataSource() - setSnapShot() + setBindings() } } // MARK: - Methods -extension MyInfoViewController { +extension MyPageViewController { private func setUI() { view.backgroundColor = .ntdBlack - myInfoCollectionView.do { + collectionView.do { $0.collectionViewLayout = layout() $0.backgroundColor = .clear $0.bounces = false @@ -75,9 +84,9 @@ extension MyInfoViewController { } private func setLayout() { - view.addSubview(myInfoCollectionView) + view.addSubview(collectionView) - myInfoCollectionView.snp.makeConstraints { + collectionView.snp.makeConstraints { $0.directionalHorizontalEdges.equalTo(safeArea).inset(22) $0.directionalVerticalEdges.equalTo(safeArea) } @@ -85,11 +94,11 @@ extension MyInfoViewController { private func setupDataSource() { - let profileCellRegistration = CellRegistration {cell, _, item in + let profileCellRegistration = CellRegistration {cell, _, item in cell.configure(model: item) } - let infoCellRegistration = CellRegistration {cell, indexPath, item in + let infoCellRegistration = CellRegistration {cell, indexPath, item in guard let section = Sections(rawValue: indexPath.section) else { return } @@ -103,9 +112,9 @@ extension MyInfoViewController { } } - let headerRegistration = HeaderRegistration(elementKind: UICollectionView.elementKindSectionHeader) { _, _, _ in } + let headerRegistration = HeaderRegistration(elementKind: UICollectionView.elementKindSectionHeader) { _, _, _ in } - dataSource = DataSource(collectionView: myInfoCollectionView, cellProvider: { collectionView, indexPath, item in + dataSource = DataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in guard let section = Sections(rawValue: indexPath.section) else { return UICollectionViewCell() } @@ -126,24 +135,18 @@ extension MyInfoViewController { } } - private func setSnapShot() { - - var snapShot = SnapShot() + private func applySnapshot(data: MyPageModel) { + var snapshot = Snapshot() - defer { - dataSource?.apply(snapShot, animatingDifferences: false) + data.sections.forEach { section in + snapshot.appendSections([section]) + snapshot.appendItems(section.rows, toSection: section) } - snapShot.appendSections(Sections.allCases) - snapShot.appendItems(InfoModel.profile, toSection: .profile) - snapShot.appendItems(InfoModel.support, toSection: .support) - snapShot.appendItems(InfoModel.info, toSection: .info) - snapShot.appendItems(InfoModel.version(), toSection: .version) - + dataSource?.apply(snapshot, animatingDifferences: false) } private func layout() -> UICollectionViewLayout { - let layout = UICollectionViewCompositionalLayout { sectionIndex, env in guard let section = Sections(rawValue: sectionIndex) else { return nil } @@ -159,30 +162,40 @@ extension MyInfoViewController { return CompositionalLayout.setUpSection(layoutEnvironment: env, topContentInset: 18, bottomContentInset: 60) - } - } return layout } + + func setBindings() { + + let input = MyPageViewModelInput(viewWillAppearSubject: viewWillAppearSubject, profileCellTapped: profilCellTapped) + let output = viewModel.transform(input: input) + output.viewWillAppearSubject + .receive(on: RunLoop.main) + .sink { [weak self] in + self?.applySnapshot(data: $0) + } + .store(in: &cancelBag) + } } // MARK: - CollectionViewDelegate -extension MyInfoViewController: UICollectionViewDelegate { +extension MyPageViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { switch indexPath.section { case 0: - profileSectionSelection() + self.profileSectionSelection() case 1: - infoSectionSelection(for: indexPath, - events: [.clickGuide, .clickFaq], - urls: [.guid, .faq]) + self.infoSectionSelection(for: indexPath, + events: [.clickGuide, .clickFaq], + urls: [.guid, .faq]) case 2: - infoSectionSelection(for: indexPath, - events: [.clickNotice, .clickSuggestion, .clickQuestion, .clickTerms], - urls: [.notice, .suggestoin, .question, .service]) + self.infoSectionSelection(for: indexPath, + events: [.clickNotice, .clickSuggestion, .clickQuestion, .clickTerms], + urls: [.notice, .suggestoin, .question, .service]) default: return } @@ -190,7 +203,7 @@ extension MyInfoViewController: UICollectionViewDelegate { private func profileSectionSelection() { sendAnalyticsEvent(.clickMyInfo) { - coordinator?.showMyInfoAccountViewController() + profilCellTapped.send(()) } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift new file mode 100644 index 00000000..1ec3d6f9 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift @@ -0,0 +1,22 @@ +// +// MyPageViewModel.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +protocol MyPageViewModellPresentable {} + +protocol MyPageViewModel: ViewModel where Input == MyPageViewModelInput, Output == MyPageViewModelOutput {} + +struct MyPageViewModelInput { + let viewWillAppearSubject: PassthroughSubject + let profileCellTapped: PassthroughSubject +} + +struct MyPageViewModelOutput { + let viewWillAppearSubject: AnyPublisher +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift new file mode 100644 index 00000000..5835b96e --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift @@ -0,0 +1,40 @@ +// +// MyPageViewModelImpl.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import Foundation +import Combine + +final class MyPageViewModelImpl: MyPageViewModel { + + private weak var coordinator: MypageCoordinator? + private var cancelBag = Set() + + init(coordinator: MypageCoordinator) { + self.coordinator = coordinator + } + + func transform(input: MyPageViewModelInput) -> MyPageViewModelOutput { + let viewWillAppearSubject = input.viewWillAppearSubject + .map { _ -> MyPageModel in + return MyPageModel(sections: [ + .profile, + .support, + .info, + .version + ]) + } + .eraseToAnyPublisher() + + input.profileCellTapped + .sink { [weak self] _ in + self?.coordinator?.showMyInfoAccountViewController() + } + .store(in: &cancelBag) + + return Output(viewWillAppearSubject: viewWillAppearSubject) + } +} From 4b75ee51e9ee7e1e185f26ed14cf93e53e8d20fa Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Wed, 20 Mar 2024 22:37:00 +0900 Subject: [PATCH 04/22] =?UTF-8?q?[Fix]=20#244=20-=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iOS-NOTTODO/iOS-NOTTODO/Network/Service/BaseService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Service/BaseService.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Service/BaseService.swift index c89f452c..21968f2a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Network/Service/BaseService.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Service/BaseService.swift @@ -79,7 +79,7 @@ extension BaseService { }.eraseToAnyPublisher() } - // status codea만 사용하는 경우 + // status code만 사용하는 경우 func requestWithCombineNoResult(_ target: API) -> AnyPublisher { return Future { promise in self.provider.request(target) { response in From 32697520706316a415df02d25ebb5b91cb5d07c4 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Wed, 20 Mar 2024 22:47:25 +0900 Subject: [PATCH 05/22] =?UTF-8?q?[Fix]=20#244=20-=20=EC=95=B0=ED=94=8C?= =?UTF-8?q?=EB=A6=AC=ED=8A=9C=EB=93=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewControllers/AchievementViewController.swift | 1 - .../Achievement/ViewModel/AchievementViewModelImpl.swift | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift index 0997a85b..79906ac6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift @@ -49,7 +49,6 @@ final class AchievementViewController: UIViewController, AchievementViewModelPre super.viewWillAppear(animated) viewWillAppearSubject.send(Date()) - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.Achieve.viewAccomplish) } override func viewDidLoad() { diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewModel/AchievementViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewModel/AchievementViewModelImpl.swift index 38244c5b..05b8f4a6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewModel/AchievementViewModelImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewModel/AchievementViewModelImpl.swift @@ -33,6 +33,12 @@ final class AchievementViewModelImpl: AchievementViewModel { } .store(in: &cancelBag) + input.viewWillAppearSubject + .sink { _ in + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.Achieve.viewAccomplish) + } + .store(in: &cancelBag) + input.calendarCellTapped .filter { [weak self] date -> Bool in guard let percentage = self?.dataSource.value[date.formattedString()] else { From ad50ab6d3195f92ba04448de65cf8acb73aec6c4 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:22:37 +0900 Subject: [PATCH 06/22] =?UTF-8?q?[Feat]=20#244=20-=20custom=20navigation?= =?UTF-8?q?=20view=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/NottodoNavigationView.swift | 89 +++++++++++++++++++ .../RecommendActionViewController.swift | 40 +++------ 2 files changed, 100 insertions(+), 29 deletions(-) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift new file mode 100644 index 00000000..84dbcd3a --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift @@ -0,0 +1,89 @@ +// +// NOTTODONavigationView.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/20/24. +// + +import UIKit + +import SnapKit +import Then + +protocol NavigationDelegate: AnyObject { + func popViewController() +} + +final class NottodoNavigationView: UIView { + + // MARK: - Property + + weak var delegate: NavigationDelegate? + + // MARK: - UI Components + + private let backButton = UIButton() + private let navigationTitle = UILabel() + private let seperateView = UIView() + + override init(frame: CGRect) { + super.init(frame: .zero) + + setUI() + setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension NottodoNavigationView { + + private func setUI() { + + seperateView.do { + $0.backgroundColor = .gray2 + } + backButton.do { + $0.setBackgroundImage(.icBack, for: .normal) + $0.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside) + } + + navigationTitle.do { + $0.font = .Pretendard(.semiBold, size: 18) + $0.textColor = .white + } + } + + private func setLayout() { + self.addSubviews(backButton, navigationTitle, seperateView) + + self.snp.makeConstraints { + $0.height.equalTo(58) + } + + backButton.snp.makeConstraints { + $0.centerY.equalToSuperview() + $0.leading.equalToSuperview().inset(15) + } + + navigationTitle.snp.makeConstraints { + $0.center.equalToSuperview() + } + + seperateView.snp.makeConstraints { + $0.bottom.horizontalEdges.equalToSuperview() + $0.height.equalTo(0.7) + } + } + + func setTitle(_ text: String) { + navigationTitle.text = text + } + + @objc + private func backButtonTapped() { + delegate?.popViewController() + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/RecommendAction/ViewControllers/RecommendActionViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/RecommendAction/ViewControllers/RecommendActionViewController.swift index d73e836d..85996202 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/RecommendAction/ViewControllers/RecommendActionViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/RecommendAction/ViewControllers/RecommendActionViewController.swift @@ -43,9 +43,7 @@ final class RecommendActionViewController: UIViewController { // MARK: - UI Components - private let navigationView = UIView() - private let backButton = UIButton() - private let navigationTitle = UILabel() + private let navigationView = NottodoNavigationView() private let nextButton = UIButton() private var isTapped: Bool = false { didSet { @@ -111,15 +109,9 @@ private extension RecommendActionViewController { // $0.allowsMultipleSelection = true 생성뷰 이슈 해결 후 주석 해제 } - backButton.do { - $0.setBackgroundImage(.back, for: .normal) - $0.addTarget(self, action: #selector(backButtonDidTapped), for: .touchUpInside) - } - - navigationTitle.do { - $0.font = .Pretendard(.semiBold, size: 18) - $0.textColor = .white - $0.text = I18N.recommendNavTitle + navigationView.do { + $0.delegate = self + $0.setTitle(I18N.recommendNavTitle) } nextButton.do { @@ -135,23 +127,12 @@ private extension RecommendActionViewController { func setLayout() { view.addSubviews(navigationView, recommendActionCollectionView, nextButton) - navigationView.addSubviews(backButton, navigationTitle) navigationView.snp.makeConstraints { $0.top.equalTo(view.safeAreaLayoutGuide) $0.directionalHorizontalEdges.equalToSuperview() - $0.height.equalTo(58) - } - - backButton.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.leading.equalToSuperview().offset(15) } - - navigationTitle.snp.makeConstraints { - $0.center.equalToSuperview() - } - + recommendActionCollectionView.snp.makeConstraints { $0.top.equalTo(navigationView.snp.bottom) $0.leading.trailing.equalToSuperview() @@ -186,11 +167,6 @@ private extension RecommendActionViewController { recommendActionCollectionView.delegate = self recommendActionCollectionView.dataSource = self } - - @objc - func backButtonDidTapped() { - coordinator?.popViewController() - } } extension RecommendActionViewController: UICollectionViewDelegateFlowLayout { @@ -299,3 +275,9 @@ extension RecommendActionViewController { } } } + +extension RecommendActionViewController: NavigationDelegate { + func popViewController() { + coordinator?.popViewController() + } +} From 24b0fbb27491c921d7a3b7468d6bc3ac544fcdc1 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:24:21 +0900 Subject: [PATCH 07/22] =?UTF-8?q?[Add]=20#244=20-=20notificationCenter=20&?= =?UTF-8?q?=20UIApplication=20extension=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/NotificationCenter.swift | 34 +++++++++++++++++++ .../Global/Extensions/UIApplication+.swift | 29 ++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/NotificationCenter.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/UIApplication+.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/NotificationCenter.swift b/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/NotificationCenter.swift new file mode 100644 index 00000000..cb474fed --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/NotificationCenter.swift @@ -0,0 +1,34 @@ +// +// NotificationCenter.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/21/24. +// + +import UIKit +import Combine + +extension NotificationCenter { + + enum Notification { + case willEnterForeground + case didEnterBackground + } + + var willEnterForeground: AnyPublisher { + publisher(for: UIApplication.willEnterForegroundNotification) + .map { _ in return .willEnterForeground } + .eraseToAnyPublisher() + } + + var didEnterBackground: AnyPublisher { + publisher(for: UIApplication.didEnterBackgroundNotification) + .map { _ in return .didEnterBackground } + .eraseToAnyPublisher() + } + + var applicationState: AnyPublisher { + Publishers.Merge(willEnterForeground, didEnterBackground) + .eraseToAnyPublisher() + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/UIApplication+.swift b/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/UIApplication+.swift new file mode 100644 index 00000000..b457fca7 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/UIApplication+.swift @@ -0,0 +1,29 @@ +// +// UIApplication+.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/21/24. +// + +import UIKit + +extension UIApplication { + private static let notificationSettingsURL: URL? = { + let settingsString: String + if #available(iOS 16, *) { + settingsString = UIApplication.openNotificationSettingsURLString + } else if #available(iOS 15.4, *) { + settingsString = UIApplicationOpenNotificationSettingsURLString + } else { + settingsString = UIApplication.openSettingsURLString + } + return URL(string: settingsString) + }() + + func openAppNotificationSettings() { + guard + let url = UIApplication.notificationSettingsURL, + self.canOpenURL(url) else { return } + return open(url) + } +} From 52bb12bc5a51e33c239f4d00904a210cfd3ac3a7 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:24:55 +0900 Subject: [PATCH 08/22] =?UTF-8?q?[Feat]=20#244=20-=20myPageAccount=20MVVM?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyInfoAccountSection.swift | 9 +- .../Model/MyPageAccountModel.swift | 4 +- .../Models/MyInfoAccountModel.swift | 15 -- .../MyInfoAccountCollectionViewCell.swift | 160 ---------------- .../MyPageAccountCollectionViewCell.swift | 173 ++++++++++++++++++ ...wift => MyPageAccountViewController.swift} | 111 +++++------ .../ViewModel/MyInfoAccountViewModel.swift | 2 + .../MyPageAccountViewModelImpl.swift | 92 +++++----- 8 files changed, 279 insertions(+), 287 deletions(-) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/{Models => Model}/MyInfoAccountSection.swift (60%) delete mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift delete mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift rename iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/{MyInfoAccountViewController.swift => MyPageAccountViewController.swift} (64%) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyInfoAccountSection.swift similarity index 60% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyInfoAccountSection.swift index d6936732..ffd0df6a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountSection.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyInfoAccountSection.swift @@ -6,8 +6,7 @@ // import Foundation -// -// -//enum MyInfoSections { -// -//} + +enum MyInfoAccountSections: Int, CaseIterable { + case account, logout +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift index df33f851..73adab68 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift @@ -17,6 +17,7 @@ struct AccountRowData: Hashable { var content: String? var titleColor: UIColor = .white var isSwitch: Bool = false + var isOn: Bool = false static func userInfo() -> [AccountRowData] { return [AccountRowData(title: I18N.nickname, @@ -25,8 +26,7 @@ struct AccountRowData: Hashable { content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail()), AccountRowData(title: I18N.account, content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? "apple" : "kakao"), - AccountRowData(title: I18N.notification, - isSwitch: true)] + AccountRowData(title: I18N.notification, isSwitch: true)] } static func logout() -> [AccountRowData] { diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift deleted file mode 100644 index 4712da1d..00000000 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Models/MyInfoAccountModel.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// MyInfoAccountModel.swift -// iOS-NOTTODO -// -// Created by 김민서 on 2023/03/18. -// - -import UIKit - -struct MyInfoAccountModel: Hashable { - var nickname: String - var email: String - var account: String - var notification: Bool -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift deleted file mode 100644 index 5fe3c018..00000000 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountCollectionViewCell.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// MyInfoAccountCollectionViewCell.swift -// iOS-NOTTODO -// -// Created by JEONGEUN KIM on 3/15/24. -// - -import UIKit - -import SnapKit -import Then - -final class MyInfoAccountCollectionViewCell: UICollectionViewCell { - - // MARK: - Properties - - static let identifier = "MyInfoAccountCollectionViewCell" - - private var isNotificationAllowed: Bool { - return KeychainUtil.getBool(DefaultKeys.isNotificationAccepted) - } - - // MARK: - UI Components - - private let titleLabel = UILabel() - private let contentLabel = UILabel() - private let notificationSwitch = UISwitch() - - // MARK: - init - - override init(frame: CGRect) { - super.init(frame: .zero) - - setUI() - setLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - Methods - -extension MyInfoAccountCollectionViewCell { - - private func setUI() { - backgroundColor = .gray1 - - titleLabel.do { - $0.font = .Pretendard(.medium, size: 14) - $0.numberOfLines = 0 - $0.textAlignment = .left - } - - contentLabel.do { - $0.font = .Pretendard(.regular, size: 14) - $0.textColor = .gray6 - $0.numberOfLines = 0 - $0.textAlignment = .right - } - - notificationSwitch.do { - $0.isOn = isNotificationAllowed - $0.onTintColor = .green2 - $0.addTarget(self, action: #selector(switchTapped), for: .valueChanged) - } - } - - private func setLayout() { - contentView.addSubviews(titleLabel, contentLabel, notificationSwitch) - - titleLabel.snp.makeConstraints { - $0.leading.equalToSuperview().inset(20) - $0.centerY.equalToSuperview() - } - - contentLabel.snp.makeConstraints { - $0.trailing.equalToSuperview().inset(18) - $0.centerY.equalToSuperview() - } - - notificationSwitch.snp.makeConstraints { - $0.trailing.equalToSuperview().inset(18) - $0.centerY.equalToSuperview() - $0.height.equalTo(30) - $0.width.equalTo(50) - } - } - - func configure(data: AccountRowData) { - titleLabel.textColor = data.titleColor - titleLabel.text = data.title - - if data.isSwitch { - contentLabel.removeFromSuperview() - } else { - notificationSwitch.removeFromSuperview() - contentLabel.text = data.content - } - } -} - -extension MyInfoAccountCollectionViewCell { - - @objc - func switchTapped(_ sender: Any) { - - DispatchQueue.main.async { - do { - try self.toggleNotificationPermission() - } catch { - print("Error toggling notification permission: \(error)") - } - } - } - - private func toggleNotificationPermission() throws { - do { - try self.openAppSettings() - } catch { - throw error - } - } - - private func openAppSettings() throws { - let settingsUrl: URL - if #available(iOS 16.0, *) { - settingsUrl = URL(string: UIApplication.openNotificationSettingsURLString) ?? URL(string: "")! - } else { - settingsUrl = URL(string: UIApplication.openSettingsURLString) ?? URL(string: "")! - } - - if UIApplication.shared.canOpenURL(settingsUrl) { - UIApplication.shared.open(settingsUrl, completionHandler: { success in - print("iOS 설정 앱 열기: \(success)") - }) - } - } - - @objc - private func appWillEnterForeground() { - UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in - DispatchQueue.main.async { - KeychainUtil.setBool(settings.authorizationStatus == .authorized, forKey: DefaultKeys.isNotificationAccepted) - if let isNotificationAllowed = self?.isNotificationAllowed { - - // self?.delegate?.switchTapped(isNotificationAllowed) - } - - if KeychainUtil.getBool(DefaultKeys.isNotificationAccepted) { - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completePushOn) - } else { - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completePushOff) - } - } - } - } -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift new file mode 100644 index 00000000..9f495147 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift @@ -0,0 +1,173 @@ +// +// MyInfoAccountCollectionViewCell.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/15/24. +// + +import UIKit +import Combine + +import SnapKit +import Then + +final class MyPageAccountCollectionViewCell: UICollectionViewCell { + + // MARK: - Properties + + static let identifier = "MyPageAccountCollectionViewCell" + + // MARK: - Properties + + var switchTapped = PassthroughSubject() + var cancelBag = Set() + + // MARK: - UI Components + + private let titleLabel = UILabel() + private let contentLabel = UILabel() + private let notificationSwitch = UISwitch() + + // MARK: - init + + override init(frame: CGRect) { + super.init(frame: .zero) + + setUI() + setLayout() + setBindings() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Methods + +extension MyPageAccountCollectionViewCell { + + private func setUI() { + backgroundColor = .gray1 + + titleLabel.do { + $0.font = .Pretendard(.medium, size: 14) + $0.numberOfLines = 0 + $0.textAlignment = .left + } + + contentLabel.do { + $0.font = .Pretendard(.regular, size: 14) + $0.textColor = .gray6 + $0.numberOfLines = 0 + $0.textAlignment = .right + } + + notificationSwitch.do { + $0.onTintColor = .green2 + } + } + + private func setLayout() { + contentView.addSubviews(titleLabel, contentLabel, notificationSwitch) + + titleLabel.snp.makeConstraints { + $0.leading.equalToSuperview().inset(20) + $0.centerY.equalToSuperview() + } + + contentLabel.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(18) + $0.centerY.equalToSuperview() + } + + notificationSwitch.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(18) + $0.centerY.equalToSuperview() + $0.height.equalTo(30) + $0.width.equalTo(50) + } + } + + func configure(data: AccountRowData) { + titleLabel.textColor = data.titleColor + titleLabel.text = data.title + contentLabel.text = data.content + notificationSwitch.setOn(data.isOn, animated: true) + + notificationSwitch.isHidden = !data.isSwitch + contentLabel.isHidden = data.isSwitch + } + + func setBindings() { + notificationSwitch.tapPublisher + .sink { [weak self] isOn in + guard let self else { return } + self.switchTapped.send(isOn) + } + .store(in: &cancelBag) + } +} + +// 임시 코드 - 윤서 코드 merge 후 삭제 +extension UIControl { + func controlPublisher(for event: UIControl.Event) -> UIControl.EventPublisher { + return UIControl.EventPublisher(control: self, event: event) + } + + // Publisher + struct EventPublisher: Publisher { + typealias Output = UIControl + typealias Failure = Never + + let control: UIControl + let event: UIControl.Event + + func receive(subscriber: S) + where S: Subscriber, Never == S.Failure, UIControl == S.Input { + let subscription = EventSubscription( + control: control, + subscriber: subscriber, + event: event + ) + subscriber.receive(subscription: subscription) + } + } + + // Subscription + fileprivate class EventSubscription: Subscription + where EventSubscriber.Input == UIControl, EventSubscriber.Failure == Never { + let control: UIControl + let event: UIControl.Event + var subscriber: EventSubscriber? + + init(control: UIControl, subscriber: EventSubscriber, event: UIControl.Event) { + self.control = control + self.subscriber = subscriber + self.event = event + control.addTarget(self, action: #selector(eventDidOccur), for: event) + } + + func request(_ demand: Subscribers.Demand) {} + + func cancel() { + subscriber = nil + control.removeTarget(self, action: #selector(eventDidOccur), for: event) + } + + @objc func eventDidOccur() { + _ = subscriber?.receive(control) + } + } +} + +extension UISwitch { + var tapPublisher: AnyPublisher { + controlPublisher(for: .valueChanged) + .map { control in + guard let uiSwitch = control as? UISwitch else { return false } + return uiSwitch.isOn + } + .eraseToAnyPublisher() + } +} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift similarity index 64% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift index 47131045..3bb45fbd 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyInfoAccountViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift @@ -8,23 +8,20 @@ import UIKit import Combine -final class MyInfoAccountViewController: UIViewController { +final class MyPageAccountViewController: UIViewController { // MARK: - Property typealias CellRegistration = UICollectionView.CellRegistration typealias HeaderRegistration = UICollectionView.SupplementaryRegistration - typealias DataSource = UICollectionViewDiffableDataSource - typealias SnapShot = NSDiffableDataSourceSnapshot - - enum Sections: Int, CaseIterable { - case account, logout - } + typealias DataSource = UICollectionViewDiffableDataSource + typealias SnapShot = NSDiffableDataSourceSnapshot private let viewWillAppearSubject = PassthroughSubject() private let withdrawalTapped = PassthroughSubject() private let logoutTapped = PassthroughSubject() private let backButtonTapped = PassthroughSubject() + private let switchButtonTapped = PassthroughSubject() private var cancelBag = Set() private var dataSource: DataSource? @@ -33,11 +30,7 @@ final class MyInfoAccountViewController: UIViewController { // MARK: - UI Components private lazy var safeArea = self.view.safeAreaLayoutGuide - - private let navigationView = UIView() - private let backButton = UIButton() - private let navigationTitle = UILabel() - private let seperateView = UIView() + private let navigationView = NottodoNavigationView() private let withdrawButton = UIButton() private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) @@ -62,32 +55,29 @@ final class MyInfoAccountViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.viewAccountInfo) setUI() setLayout() setupDataSource() setBindings() } + + deinit { + cancelBag.forEach { $0.cancel() } + print("🤍 🤍 🤍🤍 🤍 deinit") + } } // MARK: - Methods -private extension MyInfoAccountViewController { +private extension MyPageAccountViewController { func setUI() { view.backgroundColor = .ntdBlack - seperateView.backgroundColor = .gray2 - backButton.do { - $0.setBackgroundImage(.icBack, for: .normal) - $0.addTarget(self, action: #selector(popBackbutton), for: .touchUpInside) - } - - navigationTitle.do { - $0.font = .Pretendard(.semiBold, size: 18) - $0.textColor = .white - $0.text = I18N.myInfoAccount + navigationView.do { + $0.setTitle(I18N.myInfoAccount) + $0.delegate = self } collectionView.do { @@ -109,28 +99,10 @@ private extension MyInfoAccountViewController { } func setLayout() { - view.addSubviews(navigationView, seperateView, collectionView, withdrawButton) - navigationView.addSubviews(backButton, navigationTitle) + view.addSubviews(navigationView, collectionView, withdrawButton) navigationView.snp.makeConstraints { - $0.top.equalTo(view.safeAreaLayoutGuide) - $0.directionalHorizontalEdges.equalToSuperview() - $0.height.equalTo(58) - } - - backButton.snp.makeConstraints { - $0.centerY.equalToSuperview() - $0.leading.equalToSuperview().offset(15) - } - - navigationTitle.snp.makeConstraints { - $0.center.equalToSuperview() - } - - seperateView.snp.makeConstraints { - $0.top.equalTo(navigationView.snp.bottom) - $0.directionalHorizontalEdges.equalToSuperview() - $0.height.equalTo(0.7) + $0.top.horizontalEdges.equalTo(safeArea) } collectionView.snp.makeConstraints { @@ -146,8 +118,14 @@ private extension MyInfoAccountViewController { } private func setupDataSource() { - let cellRegistration = CellRegistration {cell, _, item in + let cellRegistration = CellRegistration {cell, _, item in cell.configure(data: item) + cell.switchTapped + .receive(on: RunLoop.main) + .sink { [weak self] isOn in + self?.switchButtonTapped.send(isOn) + } + .store(in: &cell.cancelBag) } dataSource = DataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in @@ -158,7 +136,11 @@ private extension MyInfoAccountViewController { } private func setBindings() { - let input = MyPageAccountViewModelInput(viewWillAppearSubject: viewWillAppearSubject, withdrawalTapped: withdrawalTapped, logoutTapped: logoutTapped, backButtonTapped: backButtonTapped) + let input = MyPageAccountViewModelInput(viewWillAppearSubject: viewWillAppearSubject, + withdrawalTapped: withdrawalTapped, + logoutTapped: logoutTapped, + backButtonTapped: backButtonTapped, + switchButtonTapped: switchButtonTapped) let output = viewModel.transform(input: input) @@ -168,16 +150,23 @@ private extension MyInfoAccountViewController { self?.setSnapShot(userInfo: $0.profileData, logout: $0.logout) } .store(in: &cancelBag) + + output.openNotificationSettings + .receive(on: RunLoop.main) + .sink { + UIApplication.shared.openAppNotificationSettings() + } + .store(in: &cancelBag) } private func setSnapShot(userInfo: [AccountRowData], logout: [AccountRowData]) { var snapShot = SnapShot() - snapShot.appendSections(Sections.allCases) + snapShot.appendSections(MyInfoAccountSections.allCases) snapShot.appendItems(userInfo, toSection: .account) snapShot.appendItems(logout, toSection: .logout) - dataSource?.apply(snapShot, animatingDifferences: false) + dataSource?.applySnapshotUsingReloadData(snapShot) } private func layout() -> UICollectionViewLayout { @@ -185,27 +174,23 @@ private extension MyInfoAccountViewController { return CompositionalLayout.setUpSection(layoutEnvironment: env, topContentInset: 18) } } +} + +extension MyPageAccountViewController: UICollectionViewDelegate { + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + if indexPath.section == MyInfoAccountSections.logout.rawValue { logoutTapped.send(()) } + } +} + +extension MyPageAccountViewController: NavigationDelegate { @objc private func presentToWithdraw() { withdrawalTapped.send(()) } - @objc - private func popBackbutton() { + func popViewController() { backButtonTapped.send(()) } } - -extension MyInfoAccountViewController: UICollectionViewDelegate { - - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let section = Sections(rawValue: indexPath.section) - switch section { - case .logout: - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearLogoutModal) - logoutTapped.send(()) - default: break - } - } -} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift index bc276a48..0398f69a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyInfoAccountViewModel.swift @@ -17,8 +17,10 @@ struct MyPageAccountViewModelInput { let withdrawalTapped: PassthroughSubject let logoutTapped: PassthroughSubject let backButtonTapped: PassthroughSubject + let switchButtonTapped: PassthroughSubject } struct MyPageAccountViewModelOutput { let viewWillAppearSubject: AnyPublisher + let openNotificationSettings: AnyPublisher } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift index 799bb66e..9139a45a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift @@ -9,6 +9,7 @@ import Foundation import Combine import KakaoSDKUser +import UserNotifications final class MyPageAccountViewModelImpl: MyPageAccountViewModel { @@ -20,14 +21,37 @@ final class MyPageAccountViewModelImpl: MyPageAccountViewModel { self.coordinator = coordinator self.manager = manager } - + + private let mypageAccountModel = CurrentValueSubject(MyPageAccountModel(profileData: AccountRowData.userInfo(), logout: AccountRowData.logout())) + private let openNotificationSettings = PassthroughSubject() + func transform(input: MyPageAccountViewModelInput) -> MyPageAccountViewModelOutput { - let viewWillAppearSubject = input.viewWillAppearSubject - .map { _ -> MyPageAccountModel in - return MyPageAccountModel(profileData: AccountRowData.userInfo(), logout: AccountRowData.logout()) + let viewWillAppearAndForeground = Publishers.Merge(input.viewWillAppearSubject, NotificationCenter.default.willEnterForeground.map { _ in }) + + viewWillAppearAndForeground + .flatMap { _ in + self.getAuthorizationStatus() + .map { isAuthorized -> MyPageAccountModel in + var profileData = AccountRowData.userInfo() + let logoutData = AccountRowData.logout() + profileData[3].isOn = isAuthorized + return MyPageAccountModel(profileData: profileData, logout: logoutData) + } + .eraseToAnyPublisher() } - .eraseToAnyPublisher() + .sink(receiveValue: { [weak self] model in + guard let self = self else { return } + self.mypageAccountModel.send(model) + }) + .store(in: &cancelBag) + + input.switchButtonTapped + .sink { [weak self] _ in + guard let self = self else { return } + self.openNotificationSettings.send(()) + } + .store(in: &cancelBag) input.backButtonTapped .sink(receiveValue: { [weak self] _ in @@ -46,55 +70,39 @@ final class MyPageAccountViewModelImpl: MyPageAccountViewModel { input.logoutTapped .sink(receiveValue: { [weak self] _ in guard let self else { return } - self.coordinator?.showLogoutAlertController { - print("Tapped logout ") + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearLogoutModal) + + self.coordinator?.showLogoutAlertController { [weak self] in + self?.logout() } }) .store(in: &cancelBag) - - return Output(viewWillAppearSubject: viewWillAppearSubject) + + return Output(viewWillAppearSubject: mypageAccountModel.eraseToAnyPublisher(), openNotificationSettings: openNotificationSettings.eraseToAnyPublisher()) } - func logout() { + private func logout() { manager.logout() .sink(receiveCompletion: { event in print("completion: \(event)") - }, receiveValue: { data in - dump(data) + }, receiveValue: { [weak self] _ in + guard let self else { return } + self.coordinator?.connectAuthCoordinator(type: .logout) + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeLogout) }) .store(in: &cancelBag) } - func withdrawal() { - manager.withdrawl() - .sink(receiveCompletion: { event in - print("completion: \(event)") - }, receiveValue: { data in - dump(data) - }) - .store(in: &cancelBag) + private func getAuthorizationStatus() -> AnyPublisher { + return Future { promise in + UNUserNotificationCenter.current().getNotificationSettings { settings in + promise(.success(settings.authorizationStatus == .authorized)) + } + } + .eraseToAnyPublisher() } - // func logout() { - // if !KeychainUtil.getBool(DefaultKeys.isAppleLogin) { - // kakaoLogout() - // } - // - // AuthService.shared.deleteAuth { [weak self] _ in - // guard let self else { return } - // self.coordinator?.connectAuthCoordinator(type: .logout ) - // - // AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeLogout) - // } - // } - // - // func kakaoLogout() { - // UserApi.shared.logout {(error) in - // if let error = error { - // print(error) - // } else { - // print("logout() success.") - // } - // } - // } + deinit { + cancelBag.forEach { $0.cancel() } + } } From f7db265d0dbd36ecdd94aafa24c6653628457d53 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:25:28 +0900 Subject: [PATCH 09/22] =?UTF-8?q?[Fix]=20#244=20-=20amplitude=20viewmodel?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyPage/Model/MyPageModel.swift | 56 ++++++++++++---- .../MyPageViewController.swift | 67 +++++-------------- .../MyPage/ViewModel/MyPageViewModel.swift | 5 +- .../ViewModel/MyPageViewModelImpl.swift | 40 ++++++++--- 4 files changed, 96 insertions(+), 72 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift index 8b32b08d..3a6d0fc3 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift @@ -9,8 +9,8 @@ import UIKit struct MyPageModel: Hashable { let sections: [Section] - - enum Section: CaseIterable { + + enum Section: Int, CaseIterable { case profile, support, info, version var rows: [MyPageRowData] { @@ -25,29 +25,59 @@ struct MyPageModel: Hashable { return MyPageRowData.version() } } + var events: [AnalyticsEvent.MyInfo] { + switch self { + case .profile: + return [.clickMyInfo] + case .support: + return [.clickGuide, .clickFaq] + case .info: + return [.clickNotice, .clickSuggestion, .clickQuestion, .clickTerms] + case .version: + return [] + } + } + + var urls: [MyInfoURL] { + switch self { + case .profile: + return [] + case .support: + return [.guid, .faq] + case .info: + return [.notice, .suggestoin, .question, .service] + case .version: + return [] + } + } } } struct MyPageRowData: Hashable { - var image: UIImage? var user: String? var email: String? var title: String? - static var profile: [MyPageRowData] = [MyPageRowData(image: .imgUser, - user: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname(), - email: UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail())] + static var profile: [MyPageRowData] { + let user = UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname() + let email = UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail() + return [MyPageRowData(image: .imgUser, user: user, email: email)] + } - static let support: [MyPageRowData] = [MyPageRowData(image: .icGuide, title: I18N.guide), - MyPageRowData(image: .icQuestion1, title: I18N.oftenQuestion) + static let support: [MyPageRowData] = [ + MyPageRowData(image: .icGuide, title: I18N.guide), + MyPageRowData(image: .icQuestion1, title: I18N.oftenQuestion) ] - static let info: [MyPageRowData] = [MyPageRowData(title: I18N.notice), - MyPageRowData(title: I18N.sendFeedback), - MyPageRowData(title: I18N.inquiry), - MyPageRowData(title: I18N.policies) + static let info: [MyPageRowData] = [ + MyPageRowData(title: I18N.notice), + MyPageRowData(title: I18N.sendFeedback), + MyPageRowData(title: I18N.inquiry), + MyPageRowData(title: I18N.policies) ] - static func version() -> [MyPageRowData] { return [MyPageRowData(title: I18N.version + " " + (Utils.version ?? "1.0.0"))] } + static func version() -> [MyPageRowData] { + return [MyPageRowData(title: I18N.version + " " + (Utils.version ?? "1.0.0"))] + } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift index 9e6bb589..444e8e01 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift @@ -15,17 +15,14 @@ final class MyPageViewController: UIViewController { // MARK: - Properties + typealias Sections = MyPageModel.Section typealias CellRegistration = UICollectionView.CellRegistration typealias HeaderRegistration = UICollectionView.SupplementaryRegistration - typealias DataSource = UICollectionViewDiffableDataSource - typealias Snapshot = NSDiffableDataSourceSnapshot - - enum Sections: Int, CaseIterable { - case profile, support, info, version - } + typealias DataSource = UICollectionViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot private let viewWillAppearSubject = PassthroughSubject() - private let profilCellTapped = PassthroughSubject() + private let myPageCellTapped = PassthroughSubject() private var cancelBag = Set() private var dataSource: DataSource? @@ -58,7 +55,6 @@ final class MyPageViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.MyInfo.viewMyInfo) setUI() setLayout() setupDataSource() @@ -106,16 +102,15 @@ extension MyPageViewController { case .support: cell.configureWithIcon(with: item) case .info: - cell.configure(with: item, isHidden: false) + cell.configure(with: item) default: - cell.configure(with: item, isHidden: true) + cell.configure(with: item) } } let headerRegistration = HeaderRegistration(elementKind: UICollectionView.elementKindSectionHeader) { _, _, _ in } dataSource = DataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in - guard let section = Sections(rawValue: indexPath.section) else { return UICollectionViewCell() } switch section { @@ -169,12 +164,21 @@ extension MyPageViewController { func setBindings() { - let input = MyPageViewModelInput(viewWillAppearSubject: viewWillAppearSubject, profileCellTapped: profilCellTapped) + let input = MyPageViewModelInput(viewWillAppearSubject: viewWillAppearSubject, myPageCellTapped: myPageCellTapped) + let output = viewModel.transform(input: input) output.viewWillAppearSubject .receive(on: RunLoop.main) .sink { [weak self] in - self?.applySnapshot(data: $0) + guard let self else { return } + self.applySnapshot(data: $0) + } + .store(in: &cancelBag) + + output.openSafariController + .sink { [weak self] url in + guard let self else { return } + Utils.myInfoUrl(vc: self, url: url) } .store(in: &cancelBag) } @@ -185,41 +189,6 @@ extension MyPageViewController { extension MyPageViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - switch indexPath.section { - case 0: - self.profileSectionSelection() - case 1: - self.infoSectionSelection(for: indexPath, - events: [.clickGuide, .clickFaq], - urls: [.guid, .faq]) - case 2: - self.infoSectionSelection(for: indexPath, - events: [.clickNotice, .clickSuggestion, .clickQuestion, .clickTerms], - urls: [.notice, .suggestoin, .question, .service]) - default: - return - } - } - - private func profileSectionSelection() { - sendAnalyticsEvent(.clickMyInfo) { - profilCellTapped.send(()) - } - } - - private func infoSectionSelection(for indexPath: IndexPath, - events: [AnalyticsEvent.MyInfo], - urls: [MyInfoURL]) { - guard let item = urls.indices.contains(indexPath.item) ? urls[indexPath.item] : nil, - let event = events.indices.contains(indexPath.item) ? events[indexPath.item] : nil else { return } - - sendAnalyticsEvent(event) { - Utils.myInfoUrl(vc: self, url: item.url) - } - } - - private func sendAnalyticsEvent(_ event: AnalyticsEvent.MyInfo, action: () -> Void) { - AmplitudeAnalyticsService.shared.send(event: event) - action() + self.myPageCellTapped.send(indexPath) } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift index 1ec3d6f9..f2b30a4b 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModel.swift @@ -8,15 +8,16 @@ import Foundation import Combine -protocol MyPageViewModellPresentable {} +protocol MyPageViewModelPresentable {} protocol MyPageViewModel: ViewModel where Input == MyPageViewModelInput, Output == MyPageViewModelOutput {} struct MyPageViewModelInput { let viewWillAppearSubject: PassthroughSubject - let profileCellTapped: PassthroughSubject + let myPageCellTapped: PassthroughSubject } struct MyPageViewModelOutput { let viewWillAppearSubject: AnyPublisher + let openSafariController: AnyPublisher } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift index 5835b96e..8c57d23c 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift @@ -17,24 +17,48 @@ final class MyPageViewModelImpl: MyPageViewModel { self.coordinator = coordinator } + private let openSafariController = PassthroughSubject() + func transform(input: MyPageViewModelInput) -> MyPageViewModelOutput { + let viewWillAppearSubject = input.viewWillAppearSubject - .map { _ -> MyPageModel in - return MyPageModel(sections: [ + + .map { _ -> MyPageModel in + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.MyInfo.viewMyInfo) + + return MyPageModel(sections: [ .profile, .support, .info, .version ]) } - .eraseToAnyPublisher() + .eraseToAnyPublisher() - input.profileCellTapped - .sink { [weak self] _ in - self?.coordinator?.showMyInfoAccountViewController() + input.myPageCellTapped + .sink { [weak self] indexPath in + guard let self else { return } + guard let section = MyPageModel.Section(rawValue: indexPath.section), + indexPath.item < section.events.count else { return } + + self.sendAnalyticsEvent(section.events[indexPath.item]) + + switch section { + case .profile: + self.coordinator?.showMyInfoAccountViewController() + case .support, .info: + let url = section.urls[indexPath.item] + self.openSafariController.send(url.url) + case .version: + break + } } .store(in: &cancelBag) - - return Output(viewWillAppearSubject: viewWillAppearSubject) + + return Output(viewWillAppearSubject: viewWillAppearSubject, openSafariController: openSafariController.eraseToAnyPublisher()) + } + + private func sendAnalyticsEvent(_ event: AnalyticsEvent.MyInfo) { + AmplitudeAnalyticsService.shared.send(event: event) } } From 6f1016e24e2b9c9b54ae2e99ad28f85e52370d48 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:26:48 +0900 Subject: [PATCH 10/22] =?UTF-8?q?[Feat]=20#244=20-=20modal=20MVVM=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NottodoModalViewController.swift | 60 +++++++++---------- .../Modal/ViewModel/ModalViewModel.swift | 22 +++++++ .../Modal/ViewModel/ModalViewModelImpl.swift | 59 ++++++++++++++++++ 3 files changed, 111 insertions(+), 30 deletions(-) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/{ => ViewControllers}/NottodoModalViewController.swift (70%) create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModel.swift create mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModelImpl.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/NottodoModalViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift similarity index 70% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/NottodoModalViewController.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift index 6df688f8..70b926f6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/NottodoModalViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift @@ -9,6 +9,7 @@ import UIKit import SnapKit import KakaoSDKUser import SafariServices +import Combine enum ViewType { case quit @@ -20,8 +21,12 @@ final class NottodoModalViewController: UIViewController { // MARK: - Properties - private weak var coordinator: MypageCoordinator? - + private let viewWillAppearSubject = PassthroughSubject() + private let modalViewControllerDismiss = PassthroughSubject() + private let safariDismiss = PassthroughSubject() + private let safariPresent = PassthroughSubject() + private var viewModel: any ModalViewModel + private var viewType: ViewType? = .quit { didSet { setUI() @@ -38,8 +43,8 @@ final class NottodoModalViewController: UIViewController { // MARK: - init - init(coordinator: MypageCoordinator) { - self.coordinator = coordinator + init(viewModel: some ModalViewModel) { + self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } @@ -49,12 +54,19 @@ final class NottodoModalViewController: UIViewController { // MARK: - Life Cycle + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + viewWillAppearSubject.send(()) + } + override func viewDidLoad() { super.viewDidLoad() - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearWithdrawalModal) + setUI() setLayout() setDelegate() + setBindings() } override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -63,7 +75,7 @@ final class NottodoModalViewController: UIViewController { let location = touch.location(in: self.view) if !modalView.frame.contains(location) { - coordinator?.dismiss() + modalViewControllerDismiss.send(()) } } } @@ -96,6 +108,15 @@ extension NottodoModalViewController { withdrawView.delegate = self safariViewController.delegate = self } + + private func setBindings() { + let input = ModalViewModelInput(viewWillAppearSubject: viewWillAppearSubject, + modalDismiss: modalViewControllerDismiss, + safariDismiss: safariDismiss, + safariPresent: safariPresent) + + _ = viewModel.transform(input: input) + } } extension NottodoModalViewController: ModalDelegate { @@ -103,7 +124,7 @@ extension NottodoModalViewController: ModalDelegate { switch viewType { case .quitSurvey: self.present(safariViewController, animated: true) { - self.withdrawal() + self.safariPresent.send(()) } case .quit: viewType = .quitSurvey @@ -114,34 +135,13 @@ extension NottodoModalViewController: ModalDelegate { } func modalDismiss() { - coordinator?.dismiss() // 탈퇴 alert 취소 - } -} - -extension NottodoModalViewController { - func withdrawal() { - if !KeychainUtil.getBool(DefaultKeys.isAppleLogin) { - kakaoWithdrawal() - } - AuthService.shared.withdrawalAuth { _ in - AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeWithdrawal) - } - } - - func kakaoWithdrawal() { - UserApi.shared.unlink {(error) in - if let error = error { - print(error) - } else { - print("unlink() success.") - } - } + modalViewControllerDismiss.send(()) } } extension NottodoModalViewController: SFSafariViewControllerDelegate { func safariViewControllerDidFinish(_ controller: SFSafariViewController) { controller.delegate = nil - coordinator?.connectAuthCoordinator(type: .quitSurvey) + safariDismiss.send(.quitSurvey) } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModel.swift new file mode 100644 index 00000000..967acfea --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModel.swift @@ -0,0 +1,22 @@ +// +// ModalViewModel.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/21/24. +// + +import Foundation +import Combine + +protocol ModalViewModelPresentable {} + +protocol ModalViewModel: ViewModel where Input == ModalViewModelInput, Output == ModalViewModelOutput {} + +struct ModalViewModelInput { + let viewWillAppearSubject: PassthroughSubject + let modalDismiss: PassthroughSubject + let safariDismiss: PassthroughSubject + let safariPresent: PassthroughSubject +} + +struct ModalViewModelOutput {} diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModelImpl.swift new file mode 100644 index 00000000..f7dff969 --- /dev/null +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewModel/ModalViewModelImpl.swift @@ -0,0 +1,59 @@ +// +// ModalViewModelImpl.swift +// iOS-NOTTODO +// +// Created by JEONGEUN KIM on 3/21/24. +// + +import Foundation +import Combine + +final class ModalViewModelImpl: ModalViewModel { + + private weak var coordinator: MypageCoordinator? + private var manager: MyPageManger + private var cancelBag = Set() + + init(coordinator: MypageCoordinator, manager: MyPageManger) { + self.coordinator = coordinator + self.manager = manager + } + + func transform(input: ModalViewModelInput) -> ModalViewModelOutput { + + input.viewWillAppearSubject + .sink { _ in + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.appearWithdrawalModal) + } + .store(in: &cancelBag) + + input.modalDismiss + .sink { [weak self] _ in + self?.coordinator?.dismiss() + } + .store(in: &cancelBag) + + input.safariDismiss + .sink { [weak self] type in + self?.coordinator?.connectAuthCoordinator(type: type) + } + .store(in: &cancelBag) + + input.safariPresent + .sink { [weak self] _ in + self?.withdrawal() + } + .store(in: &cancelBag) + return Output() + } + + func withdrawal() { + manager.withdrawl() + .sink(receiveCompletion: { event in + print("completion: \(event)") + }, receiveValue: { _ in + AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeWithdrawal) + }) + .store(in: &cancelBag) + } +} From 939c4b11defda957c988f4e9c36295b823a97d51 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:27:03 +0900 Subject: [PATCH 11/22] =?UTF-8?q?[Fix]=20#244=20-=20layout=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyPage/Cells/InfoCollecitonViewCell.swift | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift index 60aad595..d7cd0ad1 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift @@ -64,20 +64,24 @@ extension InfoCollectionViewCell { private func setLayout() { contentView.addSubviews(horizontalStackView, arrowImage) + titleLabel.snp.makeConstraints { + $0.verticalEdges.equalTo(contentView).inset(15) + } + iconImage.snp.makeConstraints { - $0.size.equalTo(CGSize(width: 30, height: 30)) + $0.size.equalTo(30) + $0.centerY.equalToSuperview() } arrowImage.snp.makeConstraints { - $0.size.equalTo(CGSize(width: 24, height: 24)) + $0.size.equalTo(24) $0.centerY.equalToSuperview() $0.trailing.equalToSuperview().inset(13) } + horizontalStackView.snp.makeConstraints { - $0.top.equalToSuperview().offset(17) - $0.bottom.equalToSuperview().inset(17) + $0.top.bottom.equalToSuperview().inset(10) $0.leading.equalToSuperview().offset(20) - $0.centerY.equalToSuperview() } } @@ -91,10 +95,10 @@ extension InfoCollectionViewCell { } } - func configure(with model: MyPageRowData, isHidden: Bool) { + func configure(with model: MyPageRowData) { horizontalStackView.removeArrangedSubview(iconImage) iconImage.removeFromSuperview() titleLabel.text = model.title - arrowImage.isHidden = isHidden + arrowImage.isHidden = false } } From fb4836252ab07e9a435030edac55a2186fc33258 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:27:20 +0900 Subject: [PATCH 12/22] =?UTF-8?q?[Move]=20#244=20-=20modal=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=8F=B4=EB=8D=94=EB=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iOS-NOTTODO.xcodeproj/project.pbxproj | 92 +++++++++++++------ .../Modal/{ => View}/DeleteModalView.swift | 0 .../Modal/{ => View}/QuitModalView.swift | 0 .../Modal/{ => View}/WithdrawModalView.swift | 0 .../CommonNotificationViewController.swift | 0 5 files changed, 62 insertions(+), 30 deletions(-) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/{ => View}/DeleteModalView.swift (100%) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/{ => View}/QuitModalView.swift (100%) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/{ => View}/WithdrawModalView.swift (100%) rename iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/{ => ViewControllers}/CommonNotificationViewController.swift (100%) diff --git a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj index c34051d6..94d5a292 100644 --- a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj +++ b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj @@ -31,7 +31,7 @@ 0960C0D62A38BC8100A3D8DB /* DefaultKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960C0D52A38BC8100A3D8DB /* DefaultKeys.swift */; }; 0964BA4A2B0F6BFB00A8984B /* AuthInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0964BA492B0F6BFB00A8984B /* AuthInterceptor.swift */; }; 096980712BA40FCB00D101B9 /* MyPageAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980702BA40FCB00D101B9 /* MyPageAccountModel.swift */; }; - 0969809C2BA4198500D101B9 /* MyInfoAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */; }; + 0969809C2BA4198500D101B9 /* MyPageAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015B29C56DBA005AE3F5 /* MyPageAccountViewController.swift */; }; 096980A32BA41A6000D101B9 /* MyPageAccountViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88F12BA3F7A800FE01D4 /* MyPageAccountViewModelImpl.swift */; }; 096980AA2BA41AB000D101B9 /* MyPageViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980A92BA41AB000D101B9 /* MyPageViewModelImpl.swift */; }; 096980AC2BA41AC100D101B9 /* MyPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980AB2BA41AC100D101B9 /* MyPageViewModel.swift */; }; @@ -40,7 +40,7 @@ 096980B42BA41B1200D101B9 /* InfoCollecitonViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */; }; 096980B62BA41B2000D101B9 /* MyPageHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */; }; 096980B82BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096980B72BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift */; }; - 096C88EB2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */; }; + 096C88EB2BA3E5E500FE01D4 /* MyPageAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EA2BA3E5E500FE01D4 /* MyPageAccountCollectionViewCell.swift */; }; 096C88ED2BA3E6B700FE01D4 /* MyInfoAccountSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */; }; 096C88EF2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88EE2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift */; }; 096C88F42BA3F89D00FE01D4 /* MyPageManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C88F32BA3F89D00FE01D4 /* MyPageManger.swift */; }; @@ -50,6 +50,12 @@ 0982DE5429ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982DE5329ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift */; }; 0982DE5829AE40FB00D933D2 /* UITabBar+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982DE5729AE40FB00D933D2 /* UITabBar+.swift */; }; 0982DE5A29AE5E6000D933D2 /* CompositionalLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982DE5929AE5E6000D933D2 /* CompositionalLayout.swift */; }; + 0982E25F2BAB2B0F0002B060 /* API_KEY.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0982E25E2BAB2B0F0002B060 /* API_KEY.plist */; }; + 0982E2612BAB2FC90002B060 /* NottodoNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982E2602BAB2FC90002B060 /* NottodoNavigationView.swift */; }; + 0982E2632BAB3E080002B060 /* ModalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982E2622BAB3E080002B060 /* ModalViewModel.swift */; }; + 0982E2652BAB3E4D0002B060 /* ModalViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982E2642BAB3E4D0002B060 /* ModalViewModelImpl.swift */; }; + 0982E2702BAC00BA0002B060 /* UIApplication+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982E26F2BAC00BA0002B060 /* UIApplication+.swift */; }; + 0982E2722BAC01220002B060 /* NotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982E2712BAC01220002B060 /* NotificationCenter.swift */; }; 0987C8402B9DD4DC007EE8DE /* MissionAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0987C83F2B9DD242007EE8DE /* MissionAPI.swift */; }; 098904302B81BB3A004AAD3C /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0989042F2B81BB3A004AAD3C /* Coordinator.swift */; }; 098904322B81BB43004AAD3C /* CoordinatorDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 098904312B81BB43004AAD3C /* CoordinatorDelegate.swift */; }; @@ -147,7 +153,6 @@ 3B4E12F82A27C12F001D1EC1 /* WithdrawModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4E12F72A27C12F001D1EC1 /* WithdrawModalView.swift */; }; 3B4E12FA2A27C4DD001D1EC1 /* Pretendard-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 3B4E12F92A27C4DD001D1EC1 /* Pretendard-Bold.otf */; }; 3B50CB212A40E75400F2E761 /* AddMissionResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B50CB202A40E75400F2E761 /* AddMissionResponseDTO.swift */; }; - 3B570B342BA30E6100418250 /* API_KEY.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B570B332BA30E6100418250 /* API_KEY.plist */; }; 3B5F8F7A29BF8E8D0063A7F8 /* AddMissionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5F8F7929BF8E8D0063A7F8 /* AddMissionProtocol.swift */; }; 3B5F8F7F29BF900A0063A7F8 /* DateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5F8F7E29BF900A0063A7F8 /* DateCollectionViewCell.swift */; }; 3B5F8F8129BF90190063A7F8 /* NottodoCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5F8F8029BF90190063A7F8 /* NottodoCollectionViewCell.swift */; }; @@ -167,7 +172,6 @@ 3BEEBE972A4B048A0081C936 /* NottodoToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEEBE962A4B048A0081C936 /* NottodoToastView.swift */; }; 6C049A312A595C670085E40B /* logo.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 6C049A302A595C670085E40B /* logo.mp4 */; }; 6C16015829C40112005AE3F5 /* AuthButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16015729C40112005AE3F5 /* AuthButtonView.swift */; }; - 6C16016229C59EFD005AE3F5 /* MyInfoAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */; }; 6C44127129A35A1000313C3F /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127029A35A1000313C3F /* KakaoSDK */; }; 6C44127329A35A1000313C3F /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127229A35A1000313C3F /* KakaoSDKAuth */; }; 6C44127529A35A1000313C3F /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = 6C44127429A35A1000313C3F /* KakaoSDKCommon */; }; @@ -236,7 +240,7 @@ 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoCollecitonViewCell.swift; sourceTree = ""; }; 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageHeaderView.swift; sourceTree = ""; }; 096980B72BA41B2D00D101B9 /* MyProfileCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyProfileCollectionViewCell.swift; sourceTree = ""; }; - 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountCollectionViewCell.swift; sourceTree = ""; }; + 096C88EA2BA3E5E500FE01D4 /* MyPageAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAccountCollectionViewCell.swift; sourceTree = ""; }; 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountSection.swift; sourceTree = ""; }; 096C88EE2BA3F71E00FE01D4 /* MyInfoAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountViewModel.swift; sourceTree = ""; }; 096C88F12BA3F7A800FE01D4 /* MyPageAccountViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAccountViewModelImpl.swift; sourceTree = ""; }; @@ -247,6 +251,12 @@ 0982DE5329ADCCE000D933D2 /* HomeEmptyCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeEmptyCollectionViewCell.swift; sourceTree = ""; }; 0982DE5729AE40FB00D933D2 /* UITabBar+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBar+.swift"; sourceTree = ""; }; 0982DE5929AE5E6000D933D2 /* CompositionalLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionalLayout.swift; sourceTree = ""; }; + 0982E25E2BAB2B0F0002B060 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = API_KEY.plist; path = ../../../../Desktop/API_KEY.plist; sourceTree = ""; }; + 0982E2602BAB2FC90002B060 /* NottodoNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NottodoNavigationView.swift; sourceTree = ""; }; + 0982E2622BAB3E080002B060 /* ModalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalViewModel.swift; sourceTree = ""; }; + 0982E2642BAB3E4D0002B060 /* ModalViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalViewModelImpl.swift; sourceTree = ""; }; + 0982E26F2BAC00BA0002B060 /* UIApplication+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+.swift"; sourceTree = ""; }; + 0982E2712BAC01220002B060 /* NotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenter.swift; sourceTree = ""; }; 0987C83F2B9DD242007EE8DE /* MissionAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissionAPI.swift; sourceTree = ""; }; 0989042F2B81BB3A004AAD3C /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; 098904312B81BB43004AAD3C /* CoordinatorDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorDelegate.swift; sourceTree = ""; }; @@ -340,7 +350,6 @@ 3B4E12F72A27C12F001D1EC1 /* WithdrawModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WithdrawModalView.swift; sourceTree = ""; }; 3B4E12F92A27C4DD001D1EC1 /* Pretendard-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Bold.otf"; sourceTree = ""; }; 3B50CB202A40E75400F2E761 /* AddMissionResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMissionResponseDTO.swift; sourceTree = ""; }; - 3B570B332BA30E6100418250 /* API_KEY.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = API_KEY.plist; sourceTree = ""; }; 3B5F8F7929BF8E8D0063A7F8 /* AddMissionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddMissionProtocol.swift; sourceTree = ""; }; 3B5F8F7E29BF900A0063A7F8 /* DateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateCollectionViewCell.swift; sourceTree = ""; }; 3B5F8F8029BF90190063A7F8 /* NottodoCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NottodoCollectionViewCell.swift; sourceTree = ""; }; @@ -361,8 +370,7 @@ 3BEEBE962A4B048A0081C936 /* NottodoToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NottodoToastView.swift; sourceTree = ""; }; 6C049A302A595C670085E40B /* logo.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = logo.mp4; sourceTree = ""; }; 6C16015729C40112005AE3F5 /* AuthButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthButtonView.swift; sourceTree = ""; }; - 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountViewController.swift; sourceTree = ""; }; - 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoAccountModel.swift; sourceTree = ""; }; + 6C16015B29C56DBA005AE3F5 /* MyPageAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAccountViewController.swift; sourceTree = ""; }; 6C9628A82A22209E003ADE25 /* LogoOnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoOnboardingViewController.swift; sourceTree = ""; }; 6CA208222A18FE78001C4247 /* RecommendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendService.swift; sourceTree = ""; }; 6CA208242A18FEEA001C4247 /* RecommendAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAPI.swift; sourceTree = ""; }; @@ -524,6 +532,7 @@ isa = PBXGroup; children = ( 096980702BA40FCB00D101B9 /* MyPageAccountModel.swift */, + 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */, ); path = Model; sourceTree = ""; @@ -583,6 +592,34 @@ path = ViewModel; sourceTree = ""; }; + 0982E2662BAB44B20002B060 /* ViewModel */ = { + isa = PBXGroup; + children = ( + 0982E2622BAB3E080002B060 /* ModalViewModel.swift */, + 0982E2642BAB3E4D0002B060 /* ModalViewModelImpl.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 0982E2672BAB44C20002B060 /* View */ = { + isa = PBXGroup; + children = ( + 3B4E12F52A27C0BE001D1EC1 /* QuitModalView.swift */, + 092C09B62A48596500E9B06B /* DeleteModalView.swift */, + 3B4E12F72A27C12F001D1EC1 /* WithdrawModalView.swift */, + ); + path = View; + sourceTree = ""; + }; + 0982E2682BAB44CB0002B060 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + 3B4E12F12A27B621001D1EC1 /* NottodoModalViewController.swift */, + 09ED941A2B2ABAB7001864EF /* CommonNotificationViewController.swift */, + ); + path = ViewControllers; + sourceTree = ""; + }; 0987C83E2B9DD234007EE8DE /* Mission */ = { isa = PBXGroup; children = ( @@ -899,6 +936,8 @@ 0943A9F82A53239200614761 /* Bundle+.swift */, 3B03D0D72B0F5EF300302872 /* CGSize+.swift */, 3B80B5D42B7F304D00697250 /* adjust+.swift */, + 0982E26F2BAC00BA0002B060 /* UIApplication+.swift */, + 0982E2712BAC01220002B060 /* NotificationCenter.swift */, ); path = Extensions; sourceTree = ""; @@ -1000,7 +1039,7 @@ 3B027AA6299C359900BEB65C /* Resource */ = { isa = PBXGroup; children = ( - 3B570B332BA30E6100418250 /* API_KEY.plist */, + 0982E25E2BAB2B0F0002B060 /* API_KEY.plist */, 3B3EF2F72AF35C90001F79BC /* GoogleService-Info.plist */, 3B027A85299C31B600BEB65C /* Info.plist */, 3B027AAA299C35D000BEB65C /* Assets */, @@ -1074,12 +1113,10 @@ 3B4E12F02A27B60B001D1EC1 /* Modal */ = { isa = PBXGroup; children = ( + 0982E2682BAB44CB0002B060 /* ViewControllers */, + 0982E2672BAB44C20002B060 /* View */, 3B9532F22A284CAD006510F8 /* Protocol */, - 3B4E12F12A27B621001D1EC1 /* NottodoModalViewController.swift */, - 09ED941A2B2ABAB7001864EF /* CommonNotificationViewController.swift */, - 3B4E12F52A27C0BE001D1EC1 /* QuitModalView.swift */, - 3B4E12F72A27C12F001D1EC1 /* WithdrawModalView.swift */, - 092C09B62A48596500E9B06B /* DeleteModalView.swift */, + 0982E2662BAB44B20002B060 /* ViewModel */, ); path = Modal; sourceTree = ""; @@ -1221,7 +1258,6 @@ children = ( 0969806F2BA40FBF00D101B9 /* Model */, 096C88F02BA3F79A00FE01D4 /* ViewModel */, - 6C16016029C59EE0005AE3F5 /* Models */, 6C16015A29C56D90005AE3F5 /* ViewControllers */, ); path = MyPageAccount; @@ -1230,21 +1266,12 @@ 6C16015A29C56D90005AE3F5 /* ViewControllers */ = { isa = PBXGroup; children = ( - 6C16015B29C56DBA005AE3F5 /* MyInfoAccountViewController.swift */, - 096C88EA2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift */, + 6C16015B29C56DBA005AE3F5 /* MyPageAccountViewController.swift */, + 096C88EA2BA3E5E500FE01D4 /* MyPageAccountCollectionViewCell.swift */, ); path = ViewControllers; sourceTree = ""; }; - 6C16016029C59EE0005AE3F5 /* Models */ = { - isa = PBXGroup; - children = ( - 6C16016129C59EFD005AE3F5 /* MyInfoAccountModel.swift */, - 096C88EC2BA3E6B700FE01D4 /* MyInfoAccountSection.swift */, - ); - path = Models; - sourceTree = ""; - }; 6C9628AA2A2220E2003ADE25 /* Lottie */ = { isa = PBXGroup; children = ( @@ -1339,6 +1366,7 @@ 09022D4529C44BC300DE6E49 /* MissionCalendarCell.swift */, 0917F2B129C979A400009324 /* StackView */, 0917F2AF29C9798800009324 /* Calendar */, + 0982E2602BAB2FC90002B060 /* NottodoNavigationView.swift */, ); path = Common; sourceTree = ""; @@ -1448,7 +1476,7 @@ 3B710A5C2A62D4AB00E95620 /* Settings.bundle in Resources */, 3B027A84299C31B600BEB65C /* LaunchScreen.storyboard in Resources */, 6CC54C1A2A28C3AE00AAD76D /* value.json in Resources */, - 3B570B342BA30E6100418250 /* API_KEY.plist in Resources */, + 0982E25F2BAB2B0F0002B060 /* API_KEY.plist in Resources */, 3B3EF2F82AF35C90001F79BC /* GoogleService-Info.plist in Resources */, 6C049A312A595C670085E40B /* logo.mp4 in Resources */, 3B027A81299C31B600BEB65C /* Assets.xcassets in Resources */, @@ -1486,7 +1514,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0969809C2BA4198500D101B9 /* MyInfoAccountViewController.swift in Sources */, + 0969809C2BA4198500D101B9 /* MyPageAccountViewController.swift in Sources */, 3B03D0D62B0F15AA00302872 /* NotificationDialogViewController.swift in Sources */, 09F6719729CC81B500708725 /* DetailAchievementCollectionViewCell.swift in Sources */, 0960C0D62A38BC8100A3D8DB /* DefaultKeys.swift in Sources */, @@ -1495,13 +1523,13 @@ 09A146652A1964B500DDC308 /* AddAnotherDayResponseDTO.swift in Sources */, 3B027A7C299C31B500BEB65C /* AuthViewController.swift in Sources */, 098904382B81BC16004AAD3C /* AppCoordinator.swift in Sources */, - 6C16016229C59EFD005AE3F5 /* MyInfoAccountModel.swift in Sources */, 3B027A92299C33FE00BEB65C /* UIColor+.swift in Sources */, 092C09B52A484DD900E9B06B /* HomeDeleteViewController.swift in Sources */, 0989043B2B81BCFA004AAD3C /* AppCoordinatorImpl.swift in Sources */, 097568362A2FEF630001EC46 /* String+.swift in Sources */, 6CA2B7BB2A222D2300A9E549 /* ValueOnboardingViewController.swift in Sources */, 3B5F8F8129BF90190063A7F8 /* NottodoCollectionViewCell.swift in Sources */, + 0982E2702BAC00BA0002B060 /* UIApplication+.swift in Sources */, 3B027A94299C340600BEB65C /* UIFont+.swift in Sources */, 6CA208292A191185001C4247 /* UIImageView+.swift in Sources */, 0982DE5A29AE5E6000D933D2 /* CompositionalLayout.swift in Sources */, @@ -1509,18 +1537,21 @@ 098904442B81C18A004AAD3C /* HomeCoordinator.swift in Sources */, 095FEE122B9ED15600FF44C0 /* DetailAchieveHeaderView.swift in Sources */, 3B482FA3299EA9CB00BCF424 /* TabBarItem.swift in Sources */, + 0982E2652BAB3E4D0002B060 /* ModalViewModelImpl.swift in Sources */, 3B027AA0299C353700BEB65C /* AddMissionViewController.swift in Sources */, 09DCB84D2BA0146800B6BB74 /* DetailAchievementViewModel.swift in Sources */, 3B5F8F7A29BF8E8D0063A7F8 /* AddMissionProtocol.swift in Sources */, 09DCB8512BA0156400B6BB74 /* DetailAchievementViewModelImpl.swift in Sources */, 09F6718C29CB4AB700708725 /* SubOnboardingCollectionViewCell.swift in Sources */, 0921611D2A57D0920019CC8C /* AmplitudeAnalyticsService.swift in Sources */, + 0982E2612BAB2FC90002B060 /* NottodoNavigationView.swift in Sources */, 096980712BA40FCB00D101B9 /* MyPageAccountModel.swift in Sources */, 3B027A96299C340C00BEB65C /* UIImage+.swift in Sources */, 0921611F2A57D7BF0019CC8C /* AnalyticsEvent.swift in Sources */, 09DCCD1F2A18ED76003DCF8A /* DailyMissionResponseDTO.swift in Sources */, 6CF4707A29A7AAFF008D145C /* PaddingLabel.swift in Sources */, 6CA208272A18FFCF001C4247 /* RecommendResponseDTO.swift in Sources */, + 0982E2722BAC01220002B060 /* NotificationCenter.swift in Sources */, 3B4E12F22A27B621001D1EC1 /* NottodoModalViewController.swift in Sources */, 3B027A78299C31B500BEB65C /* AppDelegate.swift in Sources */, 3B50CB212A40E75400F2E761 /* AddMissionResponseDTO.swift in Sources */, @@ -1542,6 +1573,7 @@ 092E04B129BD9C86008A5892 /* MissionDetailCollectionViewCell.swift in Sources */, 6CF4706D29A739D9008D145C /* RecommendViewController.swift in Sources */, 3BC1A27429C9AF500088376B /* MissionHistoryCollectionViewCell.swift in Sources */, + 0982E2632BAB3E080002B060 /* ModalViewModel.swift in Sources */, 3B027A9E299C34DA00BEB65C /* HomeViewController.swift in Sources */, 09F6719029CB6AB400708725 /* OnboardingFooterView.swift in Sources */, 3B482FA9299EB95400BCF424 /* UIScreen+.swift in Sources */, @@ -1645,7 +1677,7 @@ 3B4E12F62A27C0BE001D1EC1 /* QuitModalView.swift in Sources */, 6CA208232A18FE78001C4247 /* RecommendService.swift in Sources */, 6CA208342A1956ED001C4247 /* AuthAPI.swift in Sources */, - 096C88EB2BA3E5E500FE01D4 /* MyInfoAccountCollectionViewCell.swift in Sources */, + 096C88EB2BA3E5E500FE01D4 /* MyPageAccountCollectionViewCell.swift in Sources */, 0921611B2A5727EF0019CC8C /* AnalyticsEventProtocol.swift in Sources */, 09DCB8692BA05F9E00B6BB74 /* AchievementModel.swift in Sources */, 098904542B81CA47004AAD3C /* UpdateCoordinator.swift in Sources */, diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/DeleteModalView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/DeleteModalView.swift similarity index 100% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/DeleteModalView.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/DeleteModalView.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/QuitModalView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/QuitModalView.swift similarity index 100% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/QuitModalView.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/QuitModalView.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/WithdrawModalView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/WithdrawModalView.swift similarity index 100% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/WithdrawModalView.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/View/WithdrawModalView.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/CommonNotificationViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/CommonNotificationViewController.swift similarity index 100% rename from iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/CommonNotificationViewController.swift rename to iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/CommonNotificationViewController.swift From 4f4f7aa73dd6e385499312183003b2ef7886fe1e Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 22 Mar 2024 02:27:37 +0900 Subject: [PATCH 13/22] =?UTF-8?q?[Fix]=20#244=20-=20Mypage=20Manaer=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Factory/ViewControllerFactory.swift | 11 +++--- .../ManagerInterface/MyPageManger.swift | 6 ++-- .../Network/Manager/MyPageManagerImpl.swift | 34 +++++++++++++++++-- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift index 92a3dcff..990a1bdc 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift @@ -39,7 +39,7 @@ protocol HomeFlowControllerFactory { protocol MyPageFlowControllerFactory { func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController + func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController } @@ -192,16 +192,19 @@ extension ViewControllerFactoryImpl { return viewController } - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController { + func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController { let authAPI = DefaultAuthService() let manager = MyPageManagerImpl(authAPI: authAPI) let viewModel = MyPageAccountViewModelImpl(coordinator: coordinator, manager: manager) - let viewController = MyInfoAccountViewController(viewModel: viewModel) + let viewController = MyPageAccountViewController(viewModel: viewModel) return viewController } func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController { - let viewController = NottodoModalViewController(coordinator: coordinator) + let authAPI = DefaultAuthService() + let manager = MyPageManagerImpl(authAPI: authAPI) + let viewModel = ModalViewModelImpl(coordinator: coordinator, manager: manager) + let viewController = NottodoModalViewController(viewModel: viewModel) return viewController } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift index 25a2bc24..29353be0 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/ManagerInterface/MyPageManger.swift @@ -9,6 +9,8 @@ import Foundation import Combine protocol MyPageManger { - func logout() -> AnyPublisher - func withdrawl() -> AnyPublisher + func logout() -> AnyPublisher + func withdrawl() -> AnyPublisher + func kakaoLogout() + func kakaoWithdrawal() } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift index 40114097..39de808d 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Network/Manager/MyPageManagerImpl.swift @@ -8,6 +8,8 @@ import Foundation import Combine +import KakaoSDKUser + final class MyPageManagerImpl: MyPageManger { private let authAPI: AuthServiceProtocol @@ -17,13 +19,41 @@ final class MyPageManagerImpl: MyPageManger { self.authAPI = authAPI } - func logout() -> AnyPublisher { + func logout() -> AnyPublisher { authAPI.logout() + .map { [weak self] _ in + self?.kakaoLogout() + } .eraseToAnyPublisher() } - func withdrawl() -> AnyPublisher { + func withdrawl() -> AnyPublisher { authAPI.withdrawal() + .map { [weak self] _ in + if !KeychainUtil.getBool(DefaultKeys.isAppleLogin) { + self?.kakaoWithdrawal() + } + } .eraseToAnyPublisher() } + + func kakaoLogout() { + UserApi.shared.logout {(error) in + if let error = error { + print(error) + } else { + print("logout() success.") + } + } + } + + func kakaoWithdrawal() { + UserApi.shared.unlink {(error) in + if let error = error { + print(error) + } else { + print("unlink() success.") + } + } + } } From a48c85ba8a12fec6e99a9f95db154a9fd1b680fd Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:22:52 +0900 Subject: [PATCH 14/22] =?UTF-8?q?[Fix]=20#244=20-=20mypage=20account=20?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EB=A6=AD=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Model/MyPageAccountModel.swift | 17 ++++++++--- .../MyPageAccountCollectionViewCell.swift | 14 ++++----- .../MyPageAccountViewController.swift | 30 +++++++++---------- .../MyPageAccountViewModelImpl.swift | 14 +++++---- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift index 73adab68..dda9b32e 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift @@ -13,6 +13,7 @@ struct MyPageAccountModel: Equatable { } struct AccountRowData: Hashable { + var uuid = UUID() var title: String var content: String? var titleColor: UIColor = .white @@ -20,17 +21,25 @@ struct AccountRowData: Hashable { var isOn: Bool = false static func userInfo() -> [AccountRowData] { - return [AccountRowData(title: I18N.nickname, + return [AccountRowData(title: I18N.nickname, content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname()), - AccountRowData(title: I18N.email, + AccountRowData(title: I18N.email, content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleEmail() : KeychainUtil.getKakaoEmail()), - AccountRowData(title: I18N.account, + AccountRowData(title: I18N.account, content: KeychainUtil.getBool(DefaultKeys.isAppleLogin) ? "apple" : "kakao"), AccountRowData(title: I18N.notification, isSwitch: true)] } static func logout() -> [AccountRowData] { - return [AccountRowData(title: I18N.logout, + return [AccountRowData(title: I18N.logout, titleColor: .ntdRed!)] } + + func hash(into hasher: inout Hasher) { + hasher.combine(uuid) + } + + static func ==(lhs: AccountRowData, rhs: AccountRowData) -> Bool { + return lhs.uuid == rhs.uuid + } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift index 9f495147..4b50a887 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountCollectionViewCell.swift @@ -94,13 +94,15 @@ extension MyPageAccountCollectionViewCell { titleLabel.text = data.title contentLabel.text = data.content notificationSwitch.setOn(data.isOn, animated: true) - + notificationSwitch.isHidden = !data.isSwitch contentLabel.isHidden = data.isSwitch } func setBindings() { - notificationSwitch.tapPublisher + + notificationSwitch.statePublisher + .receive(on: RunLoop.main) .sink { [weak self] isOn in guard let self else { return } self.switchTapped.send(isOn) @@ -162,12 +164,10 @@ extension UIControl { } extension UISwitch { - var tapPublisher: AnyPublisher { + var statePublisher: AnyPublisher { controlPublisher(for: .valueChanged) - .map { control in - guard let uiSwitch = control as? UISwitch else { return false } - return uiSwitch.isOn - } + .map { $0 as! UISwitch } + .map { $0.isOn } .eraseToAnyPublisher() } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift index 3bb45fbd..aeb7756d 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift @@ -61,11 +61,6 @@ final class MyPageAccountViewController: UIViewController { setupDataSource() setBindings() } - - deinit { - cancelBag.forEach { $0.cancel() } - print("🤍 🤍 🤍🤍 🤍 deinit") - } } // MARK: - Methods @@ -77,7 +72,11 @@ private extension MyPageAccountViewController { navigationView.do { $0.setTitle(I18N.myInfoAccount) - $0.delegate = self + $0.buttonTapped.sink { [weak self] _ in + guard let self else { return } + self.backButtonTapped.send(()) + } + .store(in: &navigationView.cancelBag) } collectionView.do { @@ -118,17 +117,20 @@ private extension MyPageAccountViewController { } private func setupDataSource() { - let cellRegistration = CellRegistration {cell, _, item in + + let cellRegistration = CellRegistration { [weak self] cell, _, item in cell.configure(data: item) cell.switchTapped .receive(on: RunLoop.main) .sink { [weak self] isOn in - self?.switchButtonTapped.send(isOn) + guard let self else { return } + self.switchButtonTapped.send(isOn) } .store(in: &cell.cancelBag) } dataSource = DataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in + return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) @@ -136,6 +138,7 @@ private extension MyPageAccountViewController { } private func setBindings() { + let input = MyPageAccountViewModelInput(viewWillAppearSubject: viewWillAppearSubject, withdrawalTapped: withdrawalTapped, logoutTapped: logoutTapped, @@ -147,7 +150,8 @@ private extension MyPageAccountViewController { output.viewWillAppearSubject .receive(on: RunLoop.main) .sink { [weak self] in - self?.setSnapShot(userInfo: $0.profileData, logout: $0.logout) + guard let self else { return } + self.setSnapShot(userInfo: $0.profileData, logout: $0.logout) } .store(in: &cancelBag) @@ -166,7 +170,7 @@ private extension MyPageAccountViewController { snapShot.appendItems(userInfo, toSection: .account) snapShot.appendItems(logout, toSection: .logout) - dataSource?.applySnapshotUsingReloadData(snapShot) + dataSource?.apply(snapShot, animatingDifferences: true) } private func layout() -> UICollectionViewLayout { @@ -183,14 +187,10 @@ extension MyPageAccountViewController: UICollectionViewDelegate { } } -extension MyPageAccountViewController: NavigationDelegate { +extension MyPageAccountViewController { @objc private func presentToWithdraw() { withdrawalTapped.send(()) } - - func popViewController() { - backButtonTapped.send(()) - } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift index 9139a45a..73bea7b3 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewModel/MyPageAccountViewModelImpl.swift @@ -30,12 +30,16 @@ final class MyPageAccountViewModelImpl: MyPageAccountViewModel { let viewWillAppearAndForeground = Publishers.Merge(input.viewWillAppearSubject, NotificationCenter.default.willEnterForeground.map { _ in }) viewWillAppearAndForeground - .flatMap { _ in - self.getAuthorizationStatus() + .flatMap { [weak self] _ in + guard let self = self else { + return Empty().eraseToAnyPublisher() + } + return self.getAuthorizationStatus() .map { isAuthorized -> MyPageAccountModel in var profileData = AccountRowData.userInfo() let logoutData = AccountRowData.logout() profileData[3].isOn = isAuthorized + KeychainUtil.setBool(isAuthorized, forKey: DefaultKeys.isNotificationAccepted) return MyPageAccountModel(profileData: profileData, logout: logoutData) } .eraseToAnyPublisher() @@ -45,7 +49,7 @@ final class MyPageAccountViewModelImpl: MyPageAccountViewModel { self.mypageAccountModel.send(model) }) .store(in: &cancelBag) - + input.switchButtonTapped .sink { [weak self] _ in guard let self = self else { return } @@ -103,6 +107,6 @@ final class MyPageAccountViewModelImpl: MyPageAccountViewModel { } deinit { - cancelBag.forEach { $0.cancel() } - } + cancelBag.forEach { $0.cancel() } + } } From 438c7c3a011854be85fe0b38db7376a97e09256c Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:23:28 +0900 Subject: [PATCH 15/22] =?UTF-8?q?[Fix]=20#244=20-=20mypage=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/ViewControllers/MyPageViewController.swift | 8 -------- .../MyPage/Cells/InfoCollecitonViewCell.swift | 5 ++--- .../Presentation/MyPage/Model/MyPageModel.swift | 3 ++- .../MyPage/ViewControllers/MyPageViewController.swift | 4 +--- .../MyPage/ViewModel/MyPageViewModelImpl.swift | 11 +++++++---- 5 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift deleted file mode 100644 index 546396e4..00000000 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Home/ViewControllers/MyPageViewController.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// MyPageViewController.swift -// iOS-NOTTODO -// -// Created by JEONGEUN KIM on 3/15/24. -// - -import Foundation diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift index d7cd0ad1..d925a8a5 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Cells/InfoCollecitonViewCell.swift @@ -96,9 +96,8 @@ extension InfoCollectionViewCell { } func configure(with model: MyPageRowData) { - horizontalStackView.removeArrangedSubview(iconImage) - iconImage.removeFromSuperview() + iconImage.isHidden = true titleLabel.text = model.title - arrowImage.isHidden = false + arrowImage.isHidden = model.isArrowHidden } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift index 3a6d0fc3..093e53d6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/Model/MyPageModel.swift @@ -58,6 +58,7 @@ struct MyPageRowData: Hashable { var user: String? var email: String? var title: String? + var isArrowHidden: Bool = false static var profile: [MyPageRowData] { let user = UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) ? KeychainUtil.getAppleUsername() : KeychainUtil.getKakaoNickname() @@ -78,6 +79,6 @@ struct MyPageRowData: Hashable { ] static func version() -> [MyPageRowData] { - return [MyPageRowData(title: I18N.version + " " + (Utils.version ?? "1.0.0"))] + return [MyPageRowData(title: I18N.version + " " + (Utils.version ?? "1.0.0"), isArrowHidden: true)] } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift index 444e8e01..318da1f6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewControllers/MyPageViewController.swift @@ -101,8 +101,6 @@ extension MyPageViewController { switch section { case .support: cell.configureWithIcon(with: item) - case .info: - cell.configure(with: item) default: cell.configure(with: item) } @@ -118,7 +116,7 @@ extension MyPageViewController { return collectionView.dequeueConfiguredReusableCell(using: profileCellRegistration, for: indexPath, item: item) - case .support, .info, .version: + case .support, .info, .version: return collectionView.dequeueConfiguredReusableCell(using: infoCellRegistration, for: indexPath, item: item) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift index 8c57d23c..fa3f29ba 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPage/ViewModel/MyPageViewModelImpl.swift @@ -22,7 +22,6 @@ final class MyPageViewModelImpl: MyPageViewModel { func transform(input: MyPageViewModelInput) -> MyPageViewModelOutput { let viewWillAppearSubject = input.viewWillAppearSubject - .map { _ -> MyPageModel in AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.MyInfo.viewMyInfo) @@ -37,15 +36,15 @@ final class MyPageViewModelImpl: MyPageViewModel { input.myPageCellTapped .sink { [weak self] indexPath in - guard let self else { return } + guard let self = self else { return } guard let section = MyPageModel.Section(rawValue: indexPath.section), indexPath.item < section.events.count else { return } - + guard let coordinator = self.coordinator else { return } self.sendAnalyticsEvent(section.events[indexPath.item]) switch section { case .profile: - self.coordinator?.showMyInfoAccountViewController() + coordinator.showMyInfoAccountViewController() case .support, .info: let url = section.urls[indexPath.item] self.openSafariController.send(url.url) @@ -61,4 +60,8 @@ final class MyPageViewModelImpl: MyPageViewModel { private func sendAnalyticsEvent(_ event: AnalyticsEvent.MyInfo) { AmplitudeAnalyticsService.shared.send(event: event) } + + deinit { + cancelBag.forEach { $0.cancel() } + } } From 3ae38d04c3a16f2158996c27471f62c222fcdce6 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:24:16 +0900 Subject: [PATCH 16/22] =?UTF-8?q?[Fix]=20#244=20-=20navigation=20view=20bu?= =?UTF-8?q?tton=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/NottodoNavigationView.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift index 84dbcd3a..b85d844a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/NottodoNavigationView.swift @@ -9,6 +9,7 @@ import UIKit import SnapKit import Then +import Combine protocol NavigationDelegate: AnyObject { func popViewController() @@ -19,6 +20,8 @@ final class NottodoNavigationView: UIView { // MARK: - Property weak var delegate: NavigationDelegate? + var cancelBag = Set() + var buttonTapped = PassthroughSubject() // MARK: - UI Components @@ -31,6 +34,7 @@ final class NottodoNavigationView: UIView { setUI() setLayout() + setBindings() } required init?(coder: NSCoder) { @@ -78,6 +82,14 @@ extension NottodoNavigationView { } } + private func setBindings() { + backButton.tapPublisher + .sink { [weak self] _ in + self?.buttonTapped.send(()) + } + .store(in: &cancelBag) + } + func setTitle(_ text: String) { navigationTitle.text = text } @@ -87,3 +99,10 @@ extension NottodoNavigationView { delegate?.popViewController() } } +extension UIButton { + var tapPublisher: AnyPublisher { + controlPublisher(for: .touchUpInside) + .map { _ in } + .eraseToAnyPublisher() + } +} From 46e17931d278f8ec9eb2b180982f8bb287a9b6d9 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:25:21 +0900 Subject: [PATCH 17/22] =?UTF-8?q?[Fix]=20#244=20-=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewControllers/AchievementViewController.swift | 4 ++-- .../ViewControllers/DetailAchievementViewController.swift | 2 +- .../Modal/ViewControllers/NottodoModalViewController.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift index 79906ac6..3201fe1a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/AchievementViewController.swift @@ -12,7 +12,7 @@ import FSCalendar import Then import SnapKit -final class AchievementViewController: UIViewController, AchievementViewModelPresentable { +final class AchievementViewController: UIViewController { // MARK: - Properties @@ -42,7 +42,7 @@ final class AchievementViewController: UIViewController, AchievementViewModelPre required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + // MARK: - Life Cycle override func viewWillAppear(_ animated: Bool) { diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/DetailAchievementViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/DetailAchievementViewController.swift index b20cf2c4..8f60bd44 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/DetailAchievementViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Achievement/ViewControllers/DetailAchievementViewController.swift @@ -43,7 +43,7 @@ final class DetailAchievementViewController: UIViewController { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift index 70b926f6..c34dfce6 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/Common/Modal/ViewControllers/NottodoModalViewController.swift @@ -51,7 +51,7 @@ final class NottodoModalViewController: UIViewController { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + // MARK: - Life Cycle override func viewWillAppear(_ animated: Bool) { From d125830ce8902dc6916b5a647842434303d0e8c2 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:25:36 +0900 Subject: [PATCH 18/22] =?UTF-8?q?[Del]=20#244=20-=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj index 94d5a292..66ccd8ad 100644 --- a/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj +++ b/iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj @@ -235,7 +235,6 @@ 096980A92BA41AB000D101B9 /* MyPageViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewModelImpl.swift; sourceTree = ""; }; 096980AB2BA41AC100D101B9 /* MyPageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewModel.swift; sourceTree = ""; }; 096980AD2BA41ACC00D101B9 /* MyPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageModel.swift; sourceTree = ""; }; - 096980AF2BA41ADF00D101B9 /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; 096980B12BA41AF600D101B9 /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; 096980B32BA41B1200D101B9 /* InfoCollecitonViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoCollecitonViewCell.swift; sourceTree = ""; }; 096980B52BA41B2000D101B9 /* MyPageHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageHeaderView.swift; sourceTree = ""; }; @@ -700,7 +699,6 @@ 092C09B42A484DD900E9B06B /* HomeDeleteViewController.swift */, 0930DE6129B80550007958DE /* MissionDetailViewController.swift */, 09582B4E29BEBAFA00EF3207 /* DetailCalendarViewController.swift */, - 096980AF2BA41ADF00D101B9 /* MyPageViewController.swift */, ); path = ViewControllers; sourceTree = ""; From b11005e7c53e496ec037c2b4b181154df73cc308 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 16:26:17 +0900 Subject: [PATCH 19/22] =?UTF-8?q?[Fix]=20#244=20-=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coordinator/MypageCoordinatorImpl.swift | 5 ++-- .../Factory/ViewControllerFactory.swift | 23 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift index 1743b5e8..bad6ba83 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift @@ -37,7 +37,7 @@ final class MypageCoordinatorImpl: MypageCoordinator { } func showMyInfoAccountViewController() { - let viewController = viewControllerFactory.makeMyInfoAccountViewController(coordinator: self) + let viewController = viewControllerFactory.makeMyPageAccountViewController(coordinator: self) viewController.hidesBottomBarWhenPushed = true navigationController.pushViewController(viewController, animated: true) } @@ -62,7 +62,8 @@ final class MypageCoordinatorImpl: MypageCoordinator { func connectAuthCoordinator(type: ViewType) { navigationController.dismiss(animated: true) { [weak self] in - self?.finish() + guard let self else { return } + self.finish() switch type { case .quitSurvey: KeychainUtil.removeUserInfo() diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift index 990a1bdc..386b37b5 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/ViewControllerFactory.swift @@ -7,7 +7,7 @@ import UIKit -protocol ViewControllerFactory: UpdateFlowcontrollerFactory, AuthFlowControllerFactory, HomeFlowControllerFactory, MyPageFlowControllerFactory, AchieveFlowControllerFactory, TabBarControllerFactory, AuthFlowControllerFactory {} +protocol ViewControllerFactory: UpdateFlowcontrollerFactory, AuthFlowControllerFactory, HomeFlowControllerFactory, AchieveFlowControllerFactory, TabBarControllerFactory, AuthFlowControllerFactory, MyPageFlowControllerFactory {} protocol UpdateFlowcontrollerFactory { func makeUpdateCheckViewController(coordinator: UpdateCoordinator) -> UpdateCheckViewController @@ -39,7 +39,7 @@ protocol HomeFlowControllerFactory { protocol MyPageFlowControllerFactory { func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController + func makeMyPageAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController } @@ -186,20 +186,26 @@ extension ViewControllerFactoryImpl { } // mypage extension ViewControllerFactoryImpl { - func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController { - let viewModel = MyPageViewModelImpl(coordinator: coordinator) - let viewController = MyPageViewController(viewModel: viewModel) - return viewController - } - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController { + func makeMyPageAccountViewModel(coordinator: MypageCoordinator) -> any MyPageAccountViewModel { let authAPI = DefaultAuthService() let manager = MyPageManagerImpl(authAPI: authAPI) let viewModel = MyPageAccountViewModelImpl(coordinator: coordinator, manager: manager) + return viewModel + } + + func makeMyPageAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController { + let viewModel = self.makeMyPageAccountViewModel(coordinator: coordinator) let viewController = MyPageAccountViewController(viewModel: viewModel) return viewController } + func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyPageViewController { + let viewModel = MyPageViewModelImpl(coordinator: coordinator) + let viewController = MyPageViewController(viewModel: viewModel) + return viewController + } + func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController { let authAPI = DefaultAuthService() let manager = MyPageManagerImpl(authAPI: authAPI) @@ -232,7 +238,6 @@ extension ViewControllerFactoryImpl { func makeTabBarController(_: UINavigationController) -> (UITabBarController, [UINavigationController]) { let tabBarController = TabBarController() let navigationControllers = tabBarController.setTabBarItems().map(makeNavigationController) - return (tabBarController, navigationControllers) } From 86ac90f3d15a5c16be971b8699641e64d063e7d6 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 18:34:48 +0900 Subject: [PATCH 20/22] =?UTF-8?q?[Fix]=20#244=20-=20MyPage=20Factory=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coordinator/MypageCoordinatorImpl.swift | 2 +- .../Factory/MyPageViewControllerFactory.swift | 37 ++++++++++++++++--- .../MyPageFlowControllerFactory.swift | 4 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift index bad6ba83..8dba175a 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Coordinator/MypageCoordinatorImpl.swift @@ -32,7 +32,7 @@ final class MypageCoordinatorImpl: MypageCoordinator { } func showMyInfoViewController() { - let viewController = viewControllerFactory.makeMyInfoViewController(coordinator: self) + let viewController = viewControllerFactory.makeMyPageViewController(coordinator: self) navigationController.setViewControllers([viewController], animated: true) } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/MyPageViewControllerFactory.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/MyPageViewControllerFactory.swift index 64d8812f..f41f0ebf 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/MyPageViewControllerFactory.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/MyPageViewControllerFactory.swift @@ -8,18 +8,45 @@ import Foundation extension ViewControllerFactoryImpl { - func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyInfoViewController { - let viewController = MyInfoViewController(coordinator: coordinator) + + func makeMyPageManager() -> MyPageManger { + let authAPI = DefaultAuthService() + let manager = MyPageManagerImpl(authAPI: authAPI) + return manager + } + + func makeMyPageViewModel(coordinator: MypageCoordinator) -> any MyPageViewModel { + let viewModel = MyPageViewModelImpl(coordinator: coordinator) + return viewModel + } + + func makeMyPageViewController(coordinator: MypageCoordinator) -> MyPageViewController { + let viewModel = self.makeMyPageViewModel(coordinator: coordinator) + let viewController = MyPageViewController(viewModel: viewModel) return viewController } - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController { - let viewController = MyInfoAccountViewController(coordinator: coordinator) + func makeMyPageAccountViewModel(coordinator: MypageCoordinator) -> any MyPageAccountViewModel { + let manager = self.makeMyPageManager() + let viewModel = MyPageAccountViewModelImpl(coordinator: coordinator, manager: manager) + return viewModel + } + + func makeMyPageAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController { + let viewModel = self.makeMyPageAccountViewModel(coordinator: coordinator) + let viewController = MyPageAccountViewController(viewModel: viewModel) return viewController } + func makeWithdrawViewModel(coordinator: MypageCoordinator) -> any ModalViewModel { + let manager = self.makeMyPageManager() + let viewModel = ModalViewModelImpl(coordinator: coordinator, manager: manager) + return viewModel + } + func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController { - let viewController = NottodoModalViewController(coordinator: coordinator) + let viewModel = self.makeWithdrawViewModel(coordinator: coordinator) + let viewController = NottodoModalViewController(viewModel: viewModel) return viewController } } diff --git a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/Protocol/MyPageFlowControllerFactory.swift b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/Protocol/MyPageFlowControllerFactory.swift index 0ef669c8..a2318f5b 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/Protocol/MyPageFlowControllerFactory.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Coordinator/Factory/Protocol/MyPageFlowControllerFactory.swift @@ -8,7 +8,7 @@ import Foundation protocol MyPageFlowControllerFactory { - func makeMyInfoViewController(coordinator: MypageCoordinator) -> MyInfoViewController - func makeMyInfoAccountViewController(coordinator: MypageCoordinator) -> MyInfoAccountViewController + func makeMyPageViewController(coordinator: MypageCoordinator) -> MyPageViewController + func makeMyPageAccountViewController(coordinator: MypageCoordinator) -> MyPageAccountViewController func makeWithdrawViewController(coordinator: MypageCoordinator) -> NottodoModalViewController } From 213d4431273b233727b9b81d98d356b212ec28f8 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sat, 23 Mar 2024 19:21:12 +0900 Subject: [PATCH 21/22] =?UTF-8?q?[Fix]=20#244=20-=20lint=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/MyPageAccount/Model/MyPageAccountModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift index dda9b32e..2a10b0f9 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/Model/MyPageAccountModel.swift @@ -39,7 +39,7 @@ struct AccountRowData: Hashable { hasher.combine(uuid) } - static func ==(lhs: AccountRowData, rhs: AccountRowData) -> Bool { + static func == (lhs: AccountRowData, rhs: AccountRowData) -> Bool { return lhs.uuid == rhs.uuid } } From 815fccdf8c16541b1005b87bf64863e972f729e2 Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Sun, 24 Mar 2024 15:41:52 +0900 Subject: [PATCH 22/22] =?UTF-8?q?[Fix]=20#244=20-=20nested=20closure=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewControllers/MyPageAccountViewController.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift index aeb7756d..d2f866cc 100644 --- a/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift +++ b/iOS-NOTTODO/iOS-NOTTODO/Presentation/MyPageAccount/ViewControllers/MyPageAccountViewController.swift @@ -122,9 +122,8 @@ private extension MyPageAccountViewController { cell.configure(data: item) cell.switchTapped .receive(on: RunLoop.main) - .sink { [weak self] isOn in - guard let self else { return } - self.switchButtonTapped.send(isOn) + .sink { isOn in + self?.switchButtonTapped.send(isOn) } .store(in: &cell.cancelBag) }