diff --git a/Project_Timer.xcodeproj/project.pbxproj b/Project_Timer.xcodeproj/project.pbxproj index 364660f5..c7426afd 100644 --- a/Project_Timer.xcodeproj/project.pbxproj +++ b/Project_Timer.xcodeproj/project.pbxproj @@ -46,38 +46,13 @@ 8706C32E2AEF878D00F7C842 /* TTSignupTextFieldUnderlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8706C32D2AEF878D00F7C842 /* TTSignupTextFieldUnderlineView.swift */; }; 8706C3302AEF881500F7C842 /* TTSignupTextFieldWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8706C32F2AEF881500F7C842 /* TTSignupTextFieldWarning.swift */; }; 8706C3322AEF8A0300F7C842 /* TTSignupNextButtonForMac.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8706C3312AEF8A0300F7C842 /* TTSignupNextButtonForMac.swift */; }; - 870800502B2C38F900830B39 /* ServerURLAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708004F2B2C38F900830B39 /* ServerURLAPI.swift */; }; - 870800522B2C3A0800830B39 /* ServerURLDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800512B2C3A0800830B39 /* ServerURLDTO.swift */; }; - 870800542B2C3A5400830B39 /* ServerURLRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800532B2C3A5400830B39 /* ServerURLRepository.swift */; }; - 870800562B2C3AC600830B39 /* ServerURLRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800552B2C3AC600830B39 /* ServerURLRepositoryInterface.swift */; }; - 870800582B2C3B0C00830B39 /* GetServerURLUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800572B2C3B0C00830B39 /* GetServerURLUseCase.swift */; }; - 8708005A2B2C3B5800830B39 /* GetServerURLUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800592B2C3B5800830B39 /* GetServerURLUseCaseInterface.swift */; }; - 8708005C2B2C4D2D00830B39 /* AuthAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708005B2B2C4D2D00830B39 /* AuthAPI.swift */; }; - 8708005F2B2C5F5F00830B39 /* AuthDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708005E2B2C5F5F00830B39 /* AuthDTO.swift */; }; - 870800612B2C5FDA00830B39 /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800602B2C5FDA00830B39 /* AuthRepository.swift */; }; + 870800522B2C3A0800830B39 /* ServerURLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800512B2C3A0800830B39 /* ServerURLResponse.swift */; }; + 8708005F2B2C5F5F00830B39 /* AuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708005E2B2C5F5F00830B39 /* AuthResponse.swift */; }; 870800632B2C604100830B39 /* AuthInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800622B2C604100830B39 /* AuthInfo.swift */; }; - 870800652B2C623600830B39 /* AuthRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800642B2C623600830B39 /* AuthRepositoryInterface.swift */; }; - 870800672B2C67E900830B39 /* AuthUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800662B2C67E900830B39 /* AuthUseCase.swift */; }; - 870800692B2C68EF00830B39 /* AuthUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800682B2C68EF00830B39 /* AuthUseCaseInterface.swift */; }; - 8708006B2B2CA57C00830B39 /* DailysAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708006A2B2CA57C00830B39 /* DailysAPI.swift */; }; - 8708006D2B2CA7AB00830B39 /* DailysRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708006C2B2CA7AB00830B39 /* DailysRepository.swift */; }; - 8708006F2B2CA92C00830B39 /* DailyDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708006E2B2CA92C00830B39 /* DailyDTO.swift */; }; + 8708006F2B2CA92C00830B39 /* DailyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708006E2B2CA92C00830B39 /* DailyResponse.swift */; }; 870800712B2CAD9900830B39 /* TaskHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800702B2CAD9900830B39 /* TaskHistory.swift */; }; - 870800732B2CB11B00830B39 /* DailyRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800722B2CB11B00830B39 /* DailyRepositoryInterface.swift */; }; - 870800752B2D3C9A00830B39 /* DailysUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800742B2D3C9A00830B39 /* DailysUseCase.swift */; }; - 870800772B2D41EA00830B39 /* DailysUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800762B2D41EA00830B39 /* DailysUseCaseInterface.swift */; }; - 870800792B2D4DE500830B39 /* RecordTimesAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800782B2D4DE500830B39 /* RecordTimesAPI.swift */; }; - 8708007B2B2D4F0800830B39 /* RecordTimesRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708007A2B2D4F0800830B39 /* RecordTimesRepository.swift */; }; - 8708007D2B2D503600830B39 /* RecordTimesRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708007C2B2D503600830B39 /* RecordTimesRepositoryInterface.swift */; }; - 8708007F2B2D543500830B39 /* RecordTimesUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708007E2B2D543500830B39 /* RecordTimesUseCase.swift */; }; - 870800812B2D54B500830B39 /* RecordTimesUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800802B2D54B500830B39 /* RecordTimesUseCaseInterface.swift */; }; - 870800832B2D551700830B39 /* RecordTimesDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800822B2D551700830B39 /* RecordTimesDTO.swift */; }; - 870800852B2D593400830B39 /* SyncLogAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800842B2D593400830B39 /* SyncLogAPI.swift */; }; - 870800872B2D599800830B39 /* SyncLogRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800862B2D599800830B39 /* SyncLogRepository.swift */; }; - 870800892B2D59EB00830B39 /* SyncLogDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800882B2D59EB00830B39 /* SyncLogDTO.swift */; }; - 8708008B2B2D5A4400830B39 /* SyncLogRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708008A2B2D5A4400830B39 /* SyncLogRepositoryInterface.swift */; }; - 8708008D2B2D63D300830B39 /* SyncLogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708008C2B2D63D300830B39 /* SyncLogUseCase.swift */; }; - 8708008F2B2D646C00830B39 /* SyncLogUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8708008E2B2D646C00830B39 /* SyncLogUseCaseInterface.swift */; }; + 870800832B2D551700830B39 /* RecordTimesResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800822B2D551700830B39 /* RecordTimesResponse.swift */; }; + 870800892B2D59EB00830B39 /* SyncLogResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870800882B2D59EB00830B39 /* SyncLogResponse.swift */; }; 870C70712AD4ECB700024CAC /* SigninRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870C70702AD4ECB700024CAC /* SigninRoute.swift */; }; 870C70732AD51BEB00024CAC /* PredicateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870C70722AD51BEB00024CAC /* PredicateChecker.swift */; }; 870E11752A0E226D00CFA77C /* CalendarWidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870E11742A0E226D00CFA77C /* CalendarWidgetData.swift */; }; @@ -88,8 +63,14 @@ 870F90E32AEFF7FC00854DDB /* SignupPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870F90E22AEFF7FC00854DDB /* SignupPasswordView.swift */; }; 870F90E52AEFFA9300854DDB /* SignupPasswordModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870F90E42AEFFA9300854DDB /* SignupPasswordModel.swift */; }; 870F90E72AEFFF1A00854DDB /* SignupPasswordRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 870F90E62AEFFF1A00854DDB /* SignupPasswordRoute.swift */; }; + 871616912C39956E00C4EF25 /* CheckUsernameRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871616902C39956E00C4EF25 /* CheckUsernameRequest.swift */; }; + 871616962C3A149000C4EF25 /* GetDailysUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871616952C3A149000C4EF25 /* GetDailysUseCase.swift */; }; + 8716169E2C3A604C00C4EF25 /* PostDailysUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8716169D2C3A604C00C4EF25 /* PostDailysUseCase.swift */; }; + 871616A02C3A605600C4EF25 /* PostRecordTimeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8716169F2C3A605600C4EF25 /* PostRecordTimeUseCase.swift */; }; + 871616A22C3A606C00C4EF25 /* GetRecordTimeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871616A12C3A606C00C4EF25 /* GetRecordTimeUseCase.swift */; }; + 871616A42C3A607700C4EF25 /* GetSyncLogUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871616A32C3A607700C4EF25 /* GetSyncLogUseCase.swift */; }; + 871616A62C3A91F900C4EF25 /* GetNotificationUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871616A52C3A91F900C4EF25 /* GetNotificationUseCase.swift */; }; 87163DC82ACAF2E8008D4072 /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87163DC72ACAF2E8008D4072 /* NetworkError.swift */; }; - 87163DCA2ACAF89B008D4072 /* NetworkResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87163DC92ACAF89B008D4072 /* NetworkResult.swift */; }; 87168D99299A819F003ED502 /* UserDefaults+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C82871BFCF008F7ADD /* UserDefaults+Extension.swift */; }; 87199F442882BC430017D01A /* StandardDailyGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87199F432882BC430017D01A /* StandardDailyGraphView.swift */; }; 87199F462883018C0017D01A /* TimelineDailyGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87199F452883018C0017D01A /* TimelineDailyGraphView.swift */; }; @@ -113,11 +94,23 @@ 8721C6D9296941F800410D57 /* UIScrollView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8721C6D8296941F800410D57 /* UIScrollView+Extension.swift */; }; 8721C6DB296943C500410D57 /* ChangeNextGraphButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8721C6DA296943C500410D57 /* ChangeNextGraphButton.swift */; }; 8721C6DD296944EE00410D57 /* ChangePrevGraphButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8721C6DC296944EE00410D57 /* ChangePrevGraphButton.swift */; }; + 872210422C2FEE83003B97AD /* SyncLogRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210412C2FEE83003B97AD /* SyncLogRepository.swift */; }; + 872210472C2FF676003B97AD /* SurveyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210462C2FF676003B97AD /* SurveyInfo.swift */; }; + 872210492C2FF6AF003B97AD /* FunctionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210482C2FF6AF003B97AD /* FunctionInfo.swift */; }; + 8722104B2C2FF6E7003B97AD /* UpdateHistoryInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8722104A2C2FF6E7003B97AD /* UpdateHistoryInfo.swift */; }; + 8722104D2C2FFA66003B97AD /* TTResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8722104C2C2FFA66003B97AD /* TTResponse.swift */; }; + 8722104F2C2FFD41003B97AD /* JSONDecoder+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8722104E2C2FFD41003B97AD /* JSONDecoder+Extension.swift */; }; + 872210522C3007FD003B97AD /* GetAppVersionUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210512C3007FD003B97AD /* GetAppVersionUseCase.swift */; }; + 872210552C30094F003B97AD /* GetServerURLUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210542C30094F003B97AD /* GetServerURLUseCase.swift */; }; + 872210572C3009DA003B97AD /* GetTiTiFunctionsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210562C3009DA003B97AD /* GetTiTiFunctionsUseCase.swift */; }; + 872210592C300A08003B97AD /* GetUpdateHistorysUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872210582C300A08003B97AD /* GetUpdateHistorysUseCase.swift */; }; + 8722105B2C300A5C003B97AD /* GetYoutubeLinkUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8722105A2C300A5C003B97AD /* GetYoutubeLinkUseCase.swift */; }; + 8722105D2C300A8C003B97AD /* GetSurveysUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8722105C2C300A8C003B97AD /* GetSurveysUseCase.swift */; }; 872C0EDB284ADD8300E8E3F2 /* SettingUpdateHistoryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EDA284ADD8300E8E3F2 /* SettingUpdateHistoryVC.swift */; }; 872C0EDE284AE52800E8E3F2 /* SettingFunctionsListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EDD284AE52800E8E3F2 /* SettingFunctionsListVC.swift */; }; 872C0EE1284AE57200E8E3F2 /* SettingTiTiLabVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EE0284AE57200E8E3F2 /* SettingTiTiLabVC.swift */; }; 872C0EE3284AF26A00E8E3F2 /* SettingUpdateHistoryVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EE2284AF26A00E8E3F2 /* SettingUpdateHistoryVM.swift */; }; - 872C0EE6284AF31000E8E3F2 /* UpdateInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EE5284AF31000E8E3F2 /* UpdateInfo.swift */; }; + 872C0EE6284AF31000E8E3F2 /* UpdateHistoryResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EE5284AF31000E8E3F2 /* UpdateHistoryResponse.swift */; }; 872C0EE8284AF5F600E8E3F2 /* UpdateInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 872C0EE7284AF5F600E8E3F2 /* UpdateInfoCell.swift */; }; 87306D4F2B260609001B7C14 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D1250028771AAD00018658 /* Language.swift */; }; 87306D512B26086D001B7C14 /* TLRko.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87306D502B26086D001B7C14 /* TLRko.swift */; }; @@ -130,13 +123,8 @@ 87306D712B26CC7B001B7C14 /* MiSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 87306D652B26CC79001B7C14 /* MiSans-Regular.ttf */; }; 87306D792B26CC7B001B7C14 /* MiSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 87306D692B26CC7A001B7C14 /* MiSans-Bold.ttf */; }; 87306D872B26D00A001B7C14 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FA75D7286F2AB900BAE2B2 /* Fonts.swift */; }; - 873731D12B2E92BD00D7BD9F /* NotificationAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D02B2E92BD00D7BD9F /* NotificationAPI.swift */; }; - 873731D32B2E931800D7BD9F /* NotificationRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D22B2E931800D7BD9F /* NotificationRepository.swift */; }; - 873731D52B2E938400D7BD9F /* NotificationDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D42B2E938400D7BD9F /* NotificationDTO.swift */; }; - 873731D72B2E97C100D7BD9F /* NotificationRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D62B2E97C100D7BD9F /* NotificationRepositoryInterface.swift */; }; - 873731D92B2E97FE00D7BD9F /* GetNotificationUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D82B2E97FE00D7BD9F /* GetNotificationUseCase.swift */; }; - 873731DB2B2E983500D7BD9F /* GetNotificationUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731DA2B2E983500D7BD9F /* GetNotificationUseCaseInterface.swift */; }; - 873731DD2B2E9AA900D7BD9F /* StringArrayValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731DC2B2E9AA900D7BD9F /* StringArrayValue.swift */; }; + 873731D52B2E938400D7BD9F /* NotificationResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731D42B2E938400D7BD9F /* NotificationResponse.swift */; }; + 873731DD2B2E9AA900D7BD9F /* FirebaseStringArrayValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731DC2B2E9AA900D7BD9F /* FirebaseStringArrayValue.swift */; }; 873731DF2B2EA2B000D7BD9F /* FirestoreValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873731DE2B2EA2AF00D7BD9F /* FirestoreValue.swift */; }; 873977EB288D3FAA0025EE73 /* LogDailyVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873977EA288D3FAA0025EE73 /* LogDailyVM.swift */; }; 873C197628D041DE00E02ADC /* DailyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873C197528D041DE00E02ADC /* DailyView.swift */; }; @@ -148,6 +136,9 @@ 87459708263FF0F000172C0F /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87459707263FF0F000172C0F /* Storage.swift */; }; 87476DAD28A2794B00FAD273 /* LastestVersionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87476DAC28A2794B00FAD273 /* LastestVersionInfo.swift */; }; 874964F52649590700113E25 /* StopwatchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874964F42649590700113E25 /* StopwatchVC.swift */; }; + 874B54282C158F890062D0AC /* CheckEmailExitRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874B54272C158F890062D0AC /* CheckEmailExitRequest.swift */; }; + 874B542C2C1592460062D0AC /* DailysRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874B542B2C1592460062D0AC /* DailysRepository.swift */; }; + 874B542E2C1595A00062D0AC /* RecordTimesRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874B542D2C1595A00062D0AC /* RecordTimesRepository.swift */; }; 874B9D1A25CAB233006FCD04 /* HGGGOTHICSSI_PRO_60G.otf in Resources */ = {isa = PBXBuildFile; fileRef = 874B9D1425CAB233006FCD04 /* HGGGOTHICSSI_PRO_60G.otf */; }; 874B9D1B25CAB233006FCD04 /* HGGGOTHICSSI_PRO_80G.otf in Resources */ = {isa = PBXBuildFile; fileRef = 874B9D1525CAB233006FCD04 /* HGGGOTHICSSI_PRO_80G.otf */; }; 874B9D1C25CAB233006FCD04 /* HGGGOTHICSSI_PRO_99G.otf in Resources */ = {isa = PBXBuildFile; fileRef = 874B9D1625CAB233006FCD04 /* HGGGOTHICSSI_PRO_99G.otf */; }; @@ -170,22 +161,16 @@ 875A5F792A207BA600679A72 /* NavigationBarInformationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875A5F782A207BA600679A72 /* NavigationBarInformationButton.swift */; }; 875A5F7B2A20836600679A72 /* HowToUseWidgetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875A5F7A2A20836500679A72 /* HowToUseWidgetVC.swift */; }; 875AA59C26494365005D15D6 /* TaskSelectVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875AA59B26494365005D15D6 /* TaskSelectVC.swift */; }; - 875C98BE287172A5008F7ADD /* StringValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98BD287172A5008F7ADD /* StringValue.swift */; }; + 875C98BE287172A5008F7ADD /* FirebaseStringValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98BD287172A5008F7ADD /* FirebaseStringValue.swift */; }; 875C98C1287175F7008F7ADD /* TiTiLabActionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C0287175F7008F7ADD /* TiTiLabActionDelegate.swift */; }; 875C98C3287176E4008F7ADD /* FunctionsActionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C2287176E4008F7ADD /* FunctionsActionDelegate.swift */; }; - 875C98C72871BB26008F7ADD /* YoutubeLinkInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C62871BB26008F7ADD /* YoutubeLinkInfo.swift */; }; + 875C98C72871BB26008F7ADD /* YoutubeLinkResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C62871BB26008F7ADD /* YoutubeLinkResponse.swift */; }; 875C98C92871BFCF008F7ADD /* UserDefaults+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98C82871BFCF008F7ADD /* UserDefaults+Extension.swift */; }; 875C98CB2871C0A7008F7ADD /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875C98CA2871C0A7008F7ADD /* UIImage+Extension.swift */; }; 875EDA342957E0360037A7EB /* NetworkInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875EDA332957E0360037A7EB /* NetworkInterceptor.swift */; }; 875EDA362957F9510037A7EB /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875EDA352957F9510037A7EB /* LoadingIndicator.swift */; }; - 875FAE252B1C6721008F19D2 /* AppVersionAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE242B1C6721008F19D2 /* AppVersionAPI.swift */; }; 875FAE282B1C679D008F19D2 /* AppLatestVersionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE272B1C679D008F19D2 /* AppLatestVersionInfo.swift */; }; - 875FAE2A2B1C6829008F19D2 /* AppLatestVersionDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE292B1C6829008F19D2 /* AppLatestVersionDTO.swift */; }; - 875FAE2C2B1C6B57008F19D2 /* AppLatestVersionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE2B2B1C6B57008F19D2 /* AppLatestVersionRepository.swift */; }; - 875FAE2F2B1C7067008F19D2 /* AppLatestVersionRepositoryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE2E2B1C7067008F19D2 /* AppLatestVersionRepositoryInterface.swift */; }; - 875FAE312B1C70C2008F19D2 /* GetLatestVersionUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE302B1C70C2008F19D2 /* GetLatestVersionUseCase.swift */; }; - 875FAE352B1C718D008F19D2 /* GetLatestVersionUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE342B1C718D008F19D2 /* GetLatestVersionUseCaseInterface.swift */; }; - 875FAE372B1C74AD008F19D2 /* BooleanValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE362B1C74AD008F19D2 /* BooleanValue.swift */; }; + 875FAE372B1C74AD008F19D2 /* FirebaseBooleanValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FAE362B1C74AD008F19D2 /* FirebaseBooleanValue.swift */; }; 875FBE252AC9116B00B28723 /* UITextField+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FBE242AC9116B00B28723 /* UITextField+Extension.swift */; }; 875FBE272AC91ED800B28723 /* CGPoint+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875FBE262AC91ED800B28723 /* CGPoint+Extension.swift */; }; 8760FB092A1DAFA70068CEF5 /* SettingCalendarWidgetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8760FB082A1DAFA70068CEF5 /* SettingCalendarWidgetVC.swift */; }; @@ -197,6 +182,14 @@ 8760FCBB29553F06000BCCD1 /* SyncDailysVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8760FCBA29553F06000BCCD1 /* SyncDailysVC.swift */; }; 87617E632A0CDFC800E312EA /* CalendarWidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87617E612A0CDF1700E312EA /* CalendarWidgetEntry.swift */; }; 87617E682A0CE58900E312EA /* CalendarWidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87617E662A0CE58400E312EA /* CalendarWidgetProvider.swift */; }; + 8761BDC02BCFE52E00E9281A /* FirebaseAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8761BDBF2BCFE52E00E9281A /* FirebaseAPI.swift */; }; + 8761BDC22BCFE64000E9281A /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 8761BDC12BCFE64000E9281A /* CombineMoya */; }; + 8761BDC42BCFE64000E9281A /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 8761BDC32BCFE64000E9281A /* Moya */; }; + 8761BDC62BCFE64000E9281A /* ReactiveMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 8761BDC52BCFE64000E9281A /* ReactiveMoya */; }; + 8761BDC82BCFE64000E9281A /* RxMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 8761BDC72BCFE64000E9281A /* RxMoya */; }; + 8761BDCA2BCFEA7A00E9281A /* AuthAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8761BDC92BCFEA7A00E9281A /* AuthAPI.swift */; }; + 8761BDCC2BCFEC8500E9281A /* DailysAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8761BDCB2BCFEC8500E9281A /* DailysAPI.swift */; }; + 8761BDCE2BCFEFD500E9281A /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8761BDCD2BCFEFD500E9281A /* API.swift */; }; 8765234628C76B6D00487BFB /* WeekSmallTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8765234528C76B6D00487BFB /* WeekSmallTime.swift */; }; 8765234828C76FFE00487BFB /* WeekSmallVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8765234728C76FFE00487BFB /* WeekSmallVM.swift */; }; 8765234A28C7709700487BFB /* WeekSmallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8765234928C7709700487BFB /* WeekSmallView.swift */; }; @@ -219,7 +212,12 @@ 877911B82A18903000F0A713 /* SettingListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877911B72A18903000F0A713 /* SettingListCell.swift */; }; 877911BA2A1891B100F0A713 /* SettingSwitchListVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877911B92A1891B100F0A713 /* SettingSwitchListVM.swift */; }; 877911BC2A18922400F0A713 /* SettingListCellInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877911BB2A18922400F0A713 /* SettingListCellInfo.swift */; }; - 877D69FC2871C1CB00215B6D /* SurveyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877D69FB2871C1CB00215B6D /* SurveyInfo.swift */; }; + 877BDCE12C390BCE00A50231 /* SignupUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877BDCE02C390BCE00A50231 /* SignupUseCase.swift */; }; + 877BDCE32C390C7900A50231 /* SigninUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877BDCE22C390C7900A50231 /* SigninUseCase.swift */; }; + 877BDCE52C390C8800A50231 /* CheckUsernameExitUseCsae.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877BDCE42C390C8800A50231 /* CheckUsernameExitUseCsae.swift */; }; + 877BDCE72C390C9300A50231 /* CheckEmailExitUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877BDCE62C390C9300A50231 /* CheckEmailExitUseCase.swift */; }; + 877BDCE92C390CA800A50231 /* UpdatePasswordUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877BDCE82C390CA800A50231 /* UpdatePasswordUseCase.swift */; }; + 877D69FC2871C1CB00215B6D /* SurveyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877D69FB2871C1CB00215B6D /* SurveyResponse.swift */; }; 878431AD27F6F461000A98B3 /* TodolistVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878431AC27F6F461000A98B3 /* TodolistVM.swift */; }; 87862E822B2D8C22004ED313 /* TTNotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87862E812B2D8C22004ED313 /* TTNotificationView.swift */; }; 87862E842B2D989A004ED313 /* NotificationInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87862E832B2D989A004ED313 /* NotificationInfo.swift */; }; @@ -245,7 +243,6 @@ 878B507225B6E31600B9EFD7 /* timer.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 878B507125B6E31600B9EFD7 /* timer.mp3 */; }; 878BF7ED2955E5430044C079 /* SyncDailysVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878BF7EC2955E5430044C079 /* SyncDailysVM.swift */; }; 878BF7EF2955E73C0044C079 /* SyncLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878BF7EE2955E73C0044C079 /* SyncLog.swift */; }; - 878BF7F12955F4600044C079 /* JSONDecoder+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878BF7F02955F4600044C079 /* JSONDecoder+Extension.swift */; }; 878C98BF2B78A40F0081CFAB /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87306D582B260E09001B7C14 /* Localized.swift */; }; 878C98C02B78A41A0081CFAB /* TLRkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87306D562B260AB8001B7C14 /* TLRkey.swift */; }; 878C98C12B78A41C0081CFAB /* TLRko.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87306D502B26086D001B7C14 /* TLRko.swift */; }; @@ -262,10 +259,7 @@ 87906C7F2B9BF749000EC960 /* MiSans-Normal.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 87906C7E2B9BF749000EC960 /* MiSans-Normal.ttf */; }; 87906C812B9BF759000EC960 /* MiSans-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 87906C802B9BF759000EC960 /* MiSans-Semibold.ttf */; }; 8791081F28387537005D7B10 /* NetworkURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8791081E28387537005D7B10 /* NetworkURL.swift */; }; - 87910821283875C0005D7B10 /* NetworkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87910820283875C0005D7B10 /* NetworkController.swift */; }; - 87910823283875CF005D7B10 /* NetworkProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87910822283875CF005D7B10 /* NetworkProtocols.swift */; }; 87910828283876DD005D7B10 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 87910827283876DD005D7B10 /* Alamofire */; }; - 8791082A283877A4005D7B10 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87910829283877A4005D7B10 /* Network.swift */; }; 8791082F28387D1F005D7B10 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8791082E28387D1F005D7B10 /* String+Extension.swift */; }; 8791C1F227DCD050000D6BA9 /* Notification+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8791C1F127DCD050000D6BA9 /* Notification+Extension.swift */; }; 8791C1F427DCD120000D6BA9 /* UserDefaultsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8791C1F327DCD120000D6BA9 /* UserDefaultsManager.swift */; }; @@ -308,6 +302,10 @@ 87AEF671289D23400018FCC8 /* UITabBarController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87AEF670289D23400018FCC8 /* UITabBarController+Extension.swift */; }; 87B539AB299BB710001E354C /* Versions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B539AA299BB710001E354C /* Versions.swift */; }; 87B7A53C2AC02202002AFDFE /* SigninSelectRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B7A53B2AC02202002AFDFE /* SigninSelectRoute.swift */; }; + 87B90B3A2BF4AEF600D6886E /* FirebaseRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B90B392BF4AEF600D6886E /* FirebaseRepository.swift */; }; + 87B90B3C2BF4B13D00D6886E /* AppVersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B90B3B2BF4B13D00D6886E /* AppVersionResponse.swift */; }; + 87B90B3F2BF4BC6D00D6886E /* TTErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B90B3E2BF4BC6D00D6886E /* TTErrorResponse.swift */; }; + 87B90B412BF4BFEE00D6886E /* TTProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B90B402BF4BFEE00D6886E /* TTProvider.swift */; }; 87BE88E72AD425BE0010A84A /* SigninTextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BE88E62AD425BE0010A84A /* SigninTextFieldView.swift */; }; 87BEBEE9281C17000095CD29 /* RecordsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BEBEE8281C17000095CD29 /* RecordsManager.swift */; }; 87BEBEEB281C19CA0095CD29 /* StopwatchVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BEBEEA281C19CA0095CD29 /* StopwatchVM.swift */; }; @@ -330,7 +328,7 @@ 87D4DCC52BA52CDF00BB5AAB /* ResetPasswordNicknameModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCC42BA52CDF00BB5AAB /* ResetPasswordNicknameModel.swift */; }; 87D4DCC72BA52F3800BB5AAB /* ResetPasswordInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCC62BA52F3800BB5AAB /* ResetPasswordInfo.swift */; }; 87D4DCC92BA52FC800BB5AAB /* ResetPasswordNicknameRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCC82BA52FC800BB5AAB /* ResetPasswordNicknameRoute.swift */; }; - 87D4DCCC2BA5477400BB5AAB /* ResetPasswordRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCCB2BA5477400BB5AAB /* ResetPasswordRequest.swift */; }; + 87D4DCCC2BA5477400BB5AAB /* UpdatePasswordRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCCB2BA5477400BB5AAB /* UpdatePasswordRequest.swift */; }; 87D4DCCF2BA5492700BB5AAB /* SimpleResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCCE2BA5492700BB5AAB /* SimpleResponse.swift */; }; 87D4DCD22BA5A4C400BB5AAB /* ResetPasswordEmailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCD12BA5A4C400BB5AAB /* ResetPasswordEmailView.swift */; }; 87D4DCD42BA5A53F00BB5AAB /* ResetPasswordEmailModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DCD32BA5A53F00BB5AAB /* ResetPasswordEmailModel.swift */; }; @@ -348,9 +346,8 @@ 87D4DE122A0F83A500993C5C /* CalendarWidgetTaskData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D4DE102A0F83A500993C5C /* CalendarWidgetTaskData.swift */; }; 87D5E65028C7460100D53F8D /* MonthSmallVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D5E64F28C7460100D53F8D /* MonthSmallVM.swift */; }; 87D5E65328C7477100D53F8D /* MonthTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D5E65228C7477100D53F8D /* MonthTime.swift */; }; - 87D7ED152952B3C100121DE6 /* TestUserSignupInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D7ED142952B3C100121DE6 /* TestUserSignupInfo.swift */; }; - 87D7ED172952B69200121DE6 /* TestUserSigninInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D7ED162952B69200121DE6 /* TestUserSigninInfo.swift */; }; - 87D7ED1A2952BA8800121DE6 /* JSONParameterEncoder+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D7ED192952BA8800121DE6 /* JSONParameterEncoder+Extension.swift */; }; + 87D7ED152952B3C100121DE6 /* TestUserSignupRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D7ED142952B3C100121DE6 /* TestUserSignupRequest.swift */; }; + 87D7ED172952B69200121DE6 /* TestUserSigninRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D7ED162952B69200121DE6 /* TestUserSigninRequest.swift */; }; 87D83E852B285D4D003C40AE /* SettingLanguageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D83E842B285D4D003C40AE /* SettingLanguageVC.swift */; }; 87D83E882B296069003C40AE /* TTSettingSelectableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D83E872B296069003C40AE /* TTSettingSelectableCell.swift */; }; 87D83E8A2B2964EC003C40AE /* SettingLanguageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D83E892B2964EC003C40AE /* SettingLanguageListView.swift */; }; @@ -380,11 +377,12 @@ 87F10930284C4337002E31EA /* TiTiLabHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F1092F284C4337002E31EA /* TiTiLabHeaderView.swift */; }; 87F10932284C4367002E31EA /* SurveyCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10931284C4367002E31EA /* SurveyCell.swift */; }; 87F10936284C47A1002E31EA /* SettingTiTiLabVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10935284C47A1002E31EA /* SettingTiTiLabVM.swift */; }; - 87F1093A284C589A002E31EA /* FunctionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10938284C589A002E31EA /* FunctionInfo.swift */; }; + 87F1093A284C589A002E31EA /* FunctionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10938284C589A002E31EA /* FunctionResponse.swift */; }; 87F1093B284C589A002E31EA /* SettingFunctionsListVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10939284C589A002E31EA /* SettingFunctionsListVM.swift */; }; 87F1093C284C589A002E31EA /* FunctionInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F10937284C589A002E31EA /* FunctionInfoCell.swift */; }; 87F50A17298FA3BD00ABF0CF /* newFeatures.strings in Resources */ = {isa = PBXBuildFile; fileRef = 87F50A19298FA3BD00ABF0CF /* newFeatures.strings */; }; 87F771BF2984101700BF1907 /* Todolist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F771BE2984101700BF1907 /* Todolist.swift */; }; + 87FB6B8D2BFE0B3F00CD7A9C /* AuthRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FB6B8C2BFE0B3F00CD7A9C /* AuthRepository.swift */; }; 87FB8D1B2B3C5DF400EA5693 /* NotificationUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FB8D1A2B3C5DF300EA5693 /* NotificationUseCase.swift */; }; 87FB8D1D2B3C5F4D00EA5693 /* NotificationUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FB8D1C2B3C5F4D00EA5693 /* NotificationUseCaseInterface.swift */; }; 87FD9FA72998D0BD00D9B0FF /* TimerStopwatchAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87FD9FA62998D0BD00D9B0FF /* TimerStopwatchAttributes.swift */; }; @@ -471,38 +469,13 @@ 8706C32D2AEF878D00F7C842 /* TTSignupTextFieldUnderlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTSignupTextFieldUnderlineView.swift; sourceTree = ""; }; 8706C32F2AEF881500F7C842 /* TTSignupTextFieldWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTSignupTextFieldWarning.swift; sourceTree = ""; }; 8706C3312AEF8A0300F7C842 /* TTSignupNextButtonForMac.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTSignupNextButtonForMac.swift; sourceTree = ""; }; - 8708004F2B2C38F900830B39 /* ServerURLAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerURLAPI.swift; sourceTree = ""; }; - 870800512B2C3A0800830B39 /* ServerURLDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerURLDTO.swift; sourceTree = ""; }; - 870800532B2C3A5400830B39 /* ServerURLRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerURLRepository.swift; sourceTree = ""; }; - 870800552B2C3AC600830B39 /* ServerURLRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerURLRepositoryInterface.swift; sourceTree = ""; }; - 870800572B2C3B0C00830B39 /* GetServerURLUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetServerURLUseCase.swift; sourceTree = ""; }; - 870800592B2C3B5800830B39 /* GetServerURLUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetServerURLUseCaseInterface.swift; sourceTree = ""; }; - 8708005B2B2C4D2D00830B39 /* AuthAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPI.swift; sourceTree = ""; }; - 8708005E2B2C5F5F00830B39 /* AuthDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthDTO.swift; sourceTree = ""; }; - 870800602B2C5FDA00830B39 /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRepository.swift; sourceTree = ""; }; + 870800512B2C3A0800830B39 /* ServerURLResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerURLResponse.swift; sourceTree = ""; }; + 8708005E2B2C5F5F00830B39 /* AuthResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResponse.swift; sourceTree = ""; }; 870800622B2C604100830B39 /* AuthInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthInfo.swift; sourceTree = ""; }; - 870800642B2C623600830B39 /* AuthRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRepositoryInterface.swift; sourceTree = ""; }; - 870800662B2C67E900830B39 /* AuthUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthUseCase.swift; sourceTree = ""; }; - 870800682B2C68EF00830B39 /* AuthUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthUseCaseInterface.swift; sourceTree = ""; }; - 8708006A2B2CA57C00830B39 /* DailysAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysAPI.swift; sourceTree = ""; }; - 8708006C2B2CA7AB00830B39 /* DailysRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysRepository.swift; sourceTree = ""; }; - 8708006E2B2CA92C00830B39 /* DailyDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyDTO.swift; sourceTree = ""; }; + 8708006E2B2CA92C00830B39 /* DailyResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyResponse.swift; sourceTree = ""; }; 870800702B2CAD9900830B39 /* TaskHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskHistory.swift; sourceTree = ""; }; - 870800722B2CB11B00830B39 /* DailyRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyRepositoryInterface.swift; sourceTree = ""; }; - 870800742B2D3C9A00830B39 /* DailysUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysUseCase.swift; sourceTree = ""; }; - 870800762B2D41EA00830B39 /* DailysUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysUseCaseInterface.swift; sourceTree = ""; }; - 870800782B2D4DE500830B39 /* RecordTimesAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesAPI.swift; sourceTree = ""; }; - 8708007A2B2D4F0800830B39 /* RecordTimesRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesRepository.swift; sourceTree = ""; }; - 8708007C2B2D503600830B39 /* RecordTimesRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesRepositoryInterface.swift; sourceTree = ""; }; - 8708007E2B2D543500830B39 /* RecordTimesUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesUseCase.swift; sourceTree = ""; }; - 870800802B2D54B500830B39 /* RecordTimesUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesUseCaseInterface.swift; sourceTree = ""; }; - 870800822B2D551700830B39 /* RecordTimesDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesDTO.swift; sourceTree = ""; }; - 870800842B2D593400830B39 /* SyncLogAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogAPI.swift; sourceTree = ""; }; - 870800862B2D599800830B39 /* SyncLogRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogRepository.swift; sourceTree = ""; }; - 870800882B2D59EB00830B39 /* SyncLogDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogDTO.swift; sourceTree = ""; }; - 8708008A2B2D5A4400830B39 /* SyncLogRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogRepositoryInterface.swift; sourceTree = ""; }; - 8708008C2B2D63D300830B39 /* SyncLogUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogUseCase.swift; sourceTree = ""; }; - 8708008E2B2D646C00830B39 /* SyncLogUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogUseCaseInterface.swift; sourceTree = ""; }; + 870800822B2D551700830B39 /* RecordTimesResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesResponse.swift; sourceTree = ""; }; + 870800882B2D59EB00830B39 /* SyncLogResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogResponse.swift; sourceTree = ""; }; 870C70702AD4ECB700024CAC /* SigninRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninRoute.swift; sourceTree = ""; }; 870C70722AD51BEB00024CAC /* PredicateChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredicateChecker.swift; sourceTree = ""; }; 870E11742A0E226D00CFA77C /* CalendarWidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarWidgetData.swift; sourceTree = ""; }; @@ -511,8 +484,14 @@ 870F90E22AEFF7FC00854DDB /* SignupPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupPasswordView.swift; sourceTree = ""; }; 870F90E42AEFFA9300854DDB /* SignupPasswordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupPasswordModel.swift; sourceTree = ""; }; 870F90E62AEFFF1A00854DDB /* SignupPasswordRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupPasswordRoute.swift; sourceTree = ""; }; + 871616902C39956E00C4EF25 /* CheckUsernameRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckUsernameRequest.swift; sourceTree = ""; }; + 871616952C3A149000C4EF25 /* GetDailysUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetDailysUseCase.swift; sourceTree = ""; }; + 8716169D2C3A604C00C4EF25 /* PostDailysUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDailysUseCase.swift; sourceTree = ""; }; + 8716169F2C3A605600C4EF25 /* PostRecordTimeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostRecordTimeUseCase.swift; sourceTree = ""; }; + 871616A12C3A606C00C4EF25 /* GetRecordTimeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetRecordTimeUseCase.swift; sourceTree = ""; }; + 871616A32C3A607700C4EF25 /* GetSyncLogUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSyncLogUseCase.swift; sourceTree = ""; }; + 871616A52C3A91F900C4EF25 /* GetNotificationUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNotificationUseCase.swift; sourceTree = ""; }; 87163DC72ACAF2E8008D4072 /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; - 87163DC92ACAF89B008D4072 /* NetworkResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResult.swift; sourceTree = ""; }; 87199F432882BC430017D01A /* StandardDailyGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardDailyGraphView.swift; sourceTree = ""; }; 87199F452883018C0017D01A /* TimelineDailyGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineDailyGraphView.swift; sourceTree = ""; }; 87199F47288303B60017D01A /* TasksProgressDailyGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksProgressDailyGraphView.swift; sourceTree = ""; }; @@ -535,12 +514,24 @@ 8721C6D8296941F800410D57 /* UIScrollView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Extension.swift"; sourceTree = ""; }; 8721C6DA296943C500410D57 /* ChangeNextGraphButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeNextGraphButton.swift; sourceTree = ""; }; 8721C6DC296944EE00410D57 /* ChangePrevGraphButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangePrevGraphButton.swift; sourceTree = ""; }; + 872210412C2FEE83003B97AD /* SyncLogRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogRepository.swift; sourceTree = ""; }; + 872210462C2FF676003B97AD /* SurveyInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyInfo.swift; sourceTree = ""; }; + 872210482C2FF6AF003B97AD /* FunctionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionInfo.swift; sourceTree = ""; }; + 8722104A2C2FF6E7003B97AD /* UpdateHistoryInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateHistoryInfo.swift; sourceTree = ""; }; + 8722104C2C2FFA66003B97AD /* TTResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTResponse.swift; sourceTree = ""; }; + 8722104E2C2FFD41003B97AD /* JSONDecoder+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extension.swift"; sourceTree = ""; }; + 872210512C3007FD003B97AD /* GetAppVersionUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAppVersionUseCase.swift; sourceTree = ""; }; + 872210542C30094F003B97AD /* GetServerURLUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetServerURLUseCase.swift; sourceTree = ""; }; + 872210562C3009DA003B97AD /* GetTiTiFunctionsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetTiTiFunctionsUseCase.swift; sourceTree = ""; }; + 872210582C300A08003B97AD /* GetUpdateHistorysUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUpdateHistorysUseCase.swift; sourceTree = ""; }; + 8722105A2C300A5C003B97AD /* GetYoutubeLinkUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetYoutubeLinkUseCase.swift; sourceTree = ""; }; + 8722105C2C300A8C003B97AD /* GetSurveysUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSurveysUseCase.swift; sourceTree = ""; }; 872B7552296A625B00D24394 /* production.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = production.xcconfig; sourceTree = ""; }; 872C0EDA284ADD8300E8E3F2 /* SettingUpdateHistoryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingUpdateHistoryVC.swift; sourceTree = ""; }; 872C0EDD284AE52800E8E3F2 /* SettingFunctionsListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingFunctionsListVC.swift; sourceTree = ""; }; 872C0EE0284AE57200E8E3F2 /* SettingTiTiLabVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingTiTiLabVC.swift; sourceTree = ""; }; 872C0EE2284AF26A00E8E3F2 /* SettingUpdateHistoryVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingUpdateHistoryVM.swift; sourceTree = ""; }; - 872C0EE5284AF31000E8E3F2 /* UpdateInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateInfo.swift; sourceTree = ""; }; + 872C0EE5284AF31000E8E3F2 /* UpdateHistoryResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateHistoryResponse.swift; sourceTree = ""; }; 872C0EE7284AF5F600E8E3F2 /* UpdateInfoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateInfoCell.swift; sourceTree = ""; }; 87306D502B26086D001B7C14 /* TLRko.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLRko.swift; sourceTree = ""; }; 87306D522B260969001B7C14 /* TLRen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLRen.swift; sourceTree = ""; }; @@ -553,13 +544,8 @@ 87306D692B26CC7A001B7C14 /* MiSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "MiSans-Bold.ttf"; sourceTree = ""; }; 873648A22B0D8CE10053B080 /* Project_TimerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Project_TimerDebug.entitlements; sourceTree = ""; }; 873648A32B0D8DDF0053B080 /* Project_TimerDevelop.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Project_TimerDevelop.entitlements; sourceTree = ""; }; - 873731D02B2E92BD00D7BD9F /* NotificationAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAPI.swift; sourceTree = ""; }; - 873731D22B2E931800D7BD9F /* NotificationRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRepository.swift; sourceTree = ""; }; - 873731D42B2E938400D7BD9F /* NotificationDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDTO.swift; sourceTree = ""; }; - 873731D62B2E97C100D7BD9F /* NotificationRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationRepositoryInterface.swift; sourceTree = ""; }; - 873731D82B2E97FE00D7BD9F /* GetNotificationUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNotificationUseCase.swift; sourceTree = ""; }; - 873731DA2B2E983500D7BD9F /* GetNotificationUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNotificationUseCaseInterface.swift; sourceTree = ""; }; - 873731DC2B2E9AA900D7BD9F /* StringArrayValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringArrayValue.swift; sourceTree = ""; }; + 873731D42B2E938400D7BD9F /* NotificationResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationResponse.swift; sourceTree = ""; }; + 873731DC2B2E9AA900D7BD9F /* FirebaseStringArrayValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseStringArrayValue.swift; sourceTree = ""; }; 873731DE2B2EA2AF00D7BD9F /* FirestoreValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirestoreValue.swift; sourceTree = ""; }; 873977EA288D3FAA0025EE73 /* LogDailyVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDailyVM.swift; sourceTree = ""; }; 873C197528D041DE00E02ADC /* DailyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyView.swift; sourceTree = ""; }; @@ -571,6 +557,9 @@ 87459707263FF0F000172C0F /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; 87476DAC28A2794B00FAD273 /* LastestVersionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastestVersionInfo.swift; sourceTree = ""; }; 874964F42649590700113E25 /* StopwatchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StopwatchVC.swift; sourceTree = ""; }; + 874B54272C158F890062D0AC /* CheckEmailExitRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckEmailExitRequest.swift; sourceTree = ""; }; + 874B542B2C1592460062D0AC /* DailysRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysRepository.swift; sourceTree = ""; }; + 874B542D2C1595A00062D0AC /* RecordTimesRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordTimesRepository.swift; sourceTree = ""; }; 874B9D1425CAB233006FCD04 /* HGGGOTHICSSI_PRO_60G.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = HGGGOTHICSSI_PRO_60G.otf; sourceTree = ""; }; 874B9D1525CAB233006FCD04 /* HGGGOTHICSSI_PRO_80G.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = HGGGOTHICSSI_PRO_80G.otf; sourceTree = ""; }; 874B9D1625CAB233006FCD04 /* HGGGOTHICSSI_PRO_99G.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = HGGGOTHICSSI_PRO_99G.otf; sourceTree = ""; }; @@ -593,22 +582,16 @@ 875A5F782A207BA600679A72 /* NavigationBarInformationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarInformationButton.swift; sourceTree = ""; }; 875A5F7A2A20836500679A72 /* HowToUseWidgetVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowToUseWidgetVC.swift; sourceTree = ""; }; 875AA59B26494365005D15D6 /* TaskSelectVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskSelectVC.swift; sourceTree = ""; }; - 875C98BD287172A5008F7ADD /* StringValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringValue.swift; sourceTree = ""; }; + 875C98BD287172A5008F7ADD /* FirebaseStringValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseStringValue.swift; sourceTree = ""; }; 875C98C0287175F7008F7ADD /* TiTiLabActionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TiTiLabActionDelegate.swift; sourceTree = ""; }; 875C98C2287176E4008F7ADD /* FunctionsActionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionsActionDelegate.swift; sourceTree = ""; }; - 875C98C62871BB26008F7ADD /* YoutubeLinkInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeLinkInfo.swift; sourceTree = ""; }; + 875C98C62871BB26008F7ADD /* YoutubeLinkResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeLinkResponse.swift; sourceTree = ""; }; 875C98C82871BFCF008F7ADD /* UserDefaults+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Extension.swift"; sourceTree = ""; }; 875C98CA2871C0A7008F7ADD /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; 875EDA332957E0360037A7EB /* NetworkInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkInterceptor.swift; sourceTree = ""; }; 875EDA352957F9510037A7EB /* LoadingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = ""; }; - 875FAE242B1C6721008F19D2 /* AppVersionAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionAPI.swift; sourceTree = ""; }; 875FAE272B1C679D008F19D2 /* AppLatestVersionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLatestVersionInfo.swift; sourceTree = ""; }; - 875FAE292B1C6829008F19D2 /* AppLatestVersionDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLatestVersionDTO.swift; sourceTree = ""; }; - 875FAE2B2B1C6B57008F19D2 /* AppLatestVersionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLatestVersionRepository.swift; sourceTree = ""; }; - 875FAE2E2B1C7067008F19D2 /* AppLatestVersionRepositoryInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLatestVersionRepositoryInterface.swift; sourceTree = ""; }; - 875FAE302B1C70C2008F19D2 /* GetLatestVersionUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetLatestVersionUseCase.swift; sourceTree = ""; }; - 875FAE342B1C718D008F19D2 /* GetLatestVersionUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetLatestVersionUseCaseInterface.swift; sourceTree = ""; }; - 875FAE362B1C74AD008F19D2 /* BooleanValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BooleanValue.swift; sourceTree = ""; }; + 875FAE362B1C74AD008F19D2 /* FirebaseBooleanValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseBooleanValue.swift; sourceTree = ""; }; 875FBE242AC9116B00B28723 /* UITextField+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Extension.swift"; sourceTree = ""; }; 875FBE262AC91ED800B28723 /* CGPoint+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extension.swift"; sourceTree = ""; }; 8760FB082A1DAFA70068CEF5 /* SettingCalendarWidgetVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingCalendarWidgetVC.swift; sourceTree = ""; }; @@ -617,6 +600,10 @@ 8760FCBA29553F06000BCCD1 /* SyncDailysVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncDailysVC.swift; sourceTree = ""; }; 87617E612A0CDF1700E312EA /* CalendarWidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarWidgetEntry.swift; sourceTree = ""; }; 87617E662A0CE58400E312EA /* CalendarWidgetProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarWidgetProvider.swift; sourceTree = ""; }; + 8761BDBF2BCFE52E00E9281A /* FirebaseAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAPI.swift; sourceTree = ""; }; + 8761BDC92BCFEA7A00E9281A /* AuthAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthAPI.swift; sourceTree = ""; }; + 8761BDCB2BCFEC8500E9281A /* DailysAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailysAPI.swift; sourceTree = ""; }; + 8761BDCD2BCFEFD500E9281A /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; 8765234528C76B6D00487BFB /* WeekSmallTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekSmallTime.swift; sourceTree = ""; }; 8765234728C76FFE00487BFB /* WeekSmallVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekSmallVM.swift; sourceTree = ""; }; 8765234928C7709700487BFB /* WeekSmallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekSmallView.swift; sourceTree = ""; }; @@ -635,7 +622,12 @@ 877911B72A18903000F0A713 /* SettingListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingListCell.swift; sourceTree = ""; }; 877911B92A1891B100F0A713 /* SettingSwitchListVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSwitchListVM.swift; sourceTree = ""; }; 877911BB2A18922400F0A713 /* SettingListCellInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingListCellInfo.swift; sourceTree = ""; }; - 877D69FB2871C1CB00215B6D /* SurveyInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyInfo.swift; sourceTree = ""; }; + 877BDCE02C390BCE00A50231 /* SignupUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupUseCase.swift; sourceTree = ""; }; + 877BDCE22C390C7900A50231 /* SigninUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninUseCase.swift; sourceTree = ""; }; + 877BDCE42C390C8800A50231 /* CheckUsernameExitUseCsae.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckUsernameExitUseCsae.swift; sourceTree = ""; }; + 877BDCE62C390C9300A50231 /* CheckEmailExitUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckEmailExitUseCase.swift; sourceTree = ""; }; + 877BDCE82C390CA800A50231 /* UpdatePasswordUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePasswordUseCase.swift; sourceTree = ""; }; + 877D69FB2871C1CB00215B6D /* SurveyResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyResponse.swift; sourceTree = ""; }; 878431AC27F6F461000A98B3 /* TodolistVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodolistVM.swift; sourceTree = ""; }; 87862E812B2D8C22004ED313 /* TTNotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTNotificationView.swift; sourceTree = ""; }; 87862E832B2D989A004ED313 /* NotificationInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationInfo.swift; sourceTree = ""; }; @@ -663,7 +655,6 @@ 878B507125B6E31600B9EFD7 /* timer.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = timer.mp3; sourceTree = ""; }; 878BF7EC2955E5430044C079 /* SyncDailysVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncDailysVM.swift; sourceTree = ""; }; 878BF7EE2955E73C0044C079 /* SyncLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLog.swift; sourceTree = ""; }; - 878BF7F02955F4600044C079 /* JSONDecoder+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extension.swift"; sourceTree = ""; }; 878DA1F52AEE617900C60CBF /* SignupInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupInfo.swift; sourceTree = ""; }; 878DA1F72AEE68DA00C60CBF /* SignupEmailModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupEmailModel.swift; sourceTree = ""; }; 878DA1FC2AEF7CEF00C60CBF /* ConfigureForTextFieldRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureForTextFieldRootView.swift; sourceTree = ""; }; @@ -675,9 +666,6 @@ 87906C7E2B9BF749000EC960 /* MiSans-Normal.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "MiSans-Normal.ttf"; sourceTree = ""; }; 87906C802B9BF759000EC960 /* MiSans-Semibold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "MiSans-Semibold.ttf"; sourceTree = ""; }; 8791081E28387537005D7B10 /* NetworkURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkURL.swift; sourceTree = ""; }; - 87910820283875C0005D7B10 /* NetworkController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkController.swift; sourceTree = ""; }; - 87910822283875CF005D7B10 /* NetworkProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtocols.swift; sourceTree = ""; }; - 87910829283877A4005D7B10 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 8791082E28387D1F005D7B10 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; 8791C1F127DCD050000D6BA9 /* Notification+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Extension.swift"; sourceTree = ""; }; 8791C1F327DCD120000D6BA9 /* UserDefaultsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsManager.swift; sourceTree = ""; }; @@ -720,6 +708,10 @@ 87AEF670289D23400018FCC8 /* UITabBarController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBarController+Extension.swift"; sourceTree = ""; }; 87B539AA299BB710001E354C /* Versions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Versions.swift; sourceTree = ""; }; 87B7A53B2AC02202002AFDFE /* SigninSelectRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninSelectRoute.swift; sourceTree = ""; }; + 87B90B392BF4AEF600D6886E /* FirebaseRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseRepository.swift; sourceTree = ""; }; + 87B90B3B2BF4B13D00D6886E /* AppVersionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionResponse.swift; sourceTree = ""; }; + 87B90B3E2BF4BC6D00D6886E /* TTErrorResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTErrorResponse.swift; sourceTree = ""; }; + 87B90B402BF4BFEE00D6886E /* TTProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTProvider.swift; sourceTree = ""; }; 87BE88E62AD425BE0010A84A /* SigninTextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninTextFieldView.swift; sourceTree = ""; }; 87BEBEE8281C17000095CD29 /* RecordsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsManager.swift; sourceTree = ""; }; 87BEBEEA281C19CA0095CD29 /* StopwatchVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StopwatchVM.swift; sourceTree = ""; }; @@ -745,14 +737,13 @@ 87D4DCC42BA52CDF00BB5AAB /* ResetPasswordNicknameModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordNicknameModel.swift; sourceTree = ""; }; 87D4DCC62BA52F3800BB5AAB /* ResetPasswordInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordInfo.swift; sourceTree = ""; }; 87D4DCC82BA52FC800BB5AAB /* ResetPasswordNicknameRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordNicknameRoute.swift; sourceTree = ""; }; - 87D4DCCB2BA5477400BB5AAB /* ResetPasswordRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordRequest.swift; sourceTree = ""; }; + 87D4DCCB2BA5477400BB5AAB /* UpdatePasswordRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePasswordRequest.swift; sourceTree = ""; }; 87D4DCCE2BA5492700BB5AAB /* SimpleResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleResponse.swift; sourceTree = ""; }; 87D4DCD12BA5A4C400BB5AAB /* ResetPasswordEmailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordEmailView.swift; sourceTree = ""; }; 87D4DCD32BA5A53F00BB5AAB /* ResetPasswordEmailModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordEmailModel.swift; sourceTree = ""; }; 87D4DCD52BA5A7B100BB5AAB /* ResetPasswordEmailRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordEmailRoute.swift; sourceTree = ""; }; 87D4DCD82BA5C17900BB5AAB /* ResetPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordView.swift; sourceTree = ""; }; 87D4DCDA2BA5C19C00BB5AAB /* ResetPasswordModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordModel.swift; sourceTree = ""; }; - 87D4DCDC2BA5C1E800BB5AAB /* ResetPasswordRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ResetPasswordRoute.swift; path = ../../../../../../../../../../Downloads/ResetPasswordRoute.swift; sourceTree = ""; }; 87D4DCDF2BA69FA500BB5AAB /* ResetPasswordCompleteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordCompleteView.swift; sourceTree = ""; }; 87D4DCE12BA6A12B00BB5AAB /* ResetPasswordCompleteModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordCompleteModel.swift; sourceTree = ""; }; 87D4DCE32BA6A18C00BB5AAB /* ChangeCompleteInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeCompleteInfo.swift; sourceTree = ""; }; @@ -762,9 +753,8 @@ 87D4DE102A0F83A500993C5C /* CalendarWidgetTaskData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarWidgetTaskData.swift; sourceTree = ""; }; 87D5E64F28C7460100D53F8D /* MonthSmallVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthSmallVM.swift; sourceTree = ""; }; 87D5E65228C7477100D53F8D /* MonthTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthTime.swift; sourceTree = ""; }; - 87D7ED142952B3C100121DE6 /* TestUserSignupInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUserSignupInfo.swift; sourceTree = ""; }; - 87D7ED162952B69200121DE6 /* TestUserSigninInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUserSigninInfo.swift; sourceTree = ""; }; - 87D7ED192952BA8800121DE6 /* JSONParameterEncoder+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONParameterEncoder+Extension.swift"; sourceTree = ""; }; + 87D7ED142952B3C100121DE6 /* TestUserSignupRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUserSignupRequest.swift; sourceTree = ""; }; + 87D7ED162952B69200121DE6 /* TestUserSigninRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUserSigninRequest.swift; sourceTree = ""; }; 87D83E842B285D4D003C40AE /* SettingLanguageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingLanguageVC.swift; sourceTree = ""; }; 87D83E872B296069003C40AE /* TTSettingSelectableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTSettingSelectableCell.swift; sourceTree = ""; }; 87D83E892B2964EC003C40AE /* SettingLanguageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingLanguageListView.swift; sourceTree = ""; }; @@ -792,11 +782,12 @@ 87F10931284C4367002E31EA /* SurveyCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyCell.swift; sourceTree = ""; }; 87F10935284C47A1002E31EA /* SettingTiTiLabVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingTiTiLabVM.swift; sourceTree = ""; }; 87F10937284C589A002E31EA /* FunctionInfoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionInfoCell.swift; sourceTree = ""; }; - 87F10938284C589A002E31EA /* FunctionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionInfo.swift; sourceTree = ""; }; + 87F10938284C589A002E31EA /* FunctionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionResponse.swift; sourceTree = ""; }; 87F10939284C589A002E31EA /* SettingFunctionsListVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingFunctionsListVM.swift; sourceTree = ""; }; 87F50A18298FA3BD00ABF0CF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/newFeatures.strings; sourceTree = ""; }; 87F50A1A298FA3C100ABF0CF /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/newFeatures.strings; sourceTree = ""; }; 87F771BE2984101700BF1907 /* Todolist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Todolist.swift; sourceTree = ""; }; + 87FB6B8C2BFE0B3F00CD7A9C /* AuthRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRepository.swift; sourceTree = ""; }; 87FB8D1A2B3C5DF300EA5693 /* NotificationUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationUseCase.swift; sourceTree = ""; }; 87FB8D1C2B3C5F4D00EA5693 /* NotificationUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationUseCaseInterface.swift; sourceTree = ""; }; 87FD9FA62998D0BD00D9B0FF /* TimerStopwatchAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerStopwatchAttributes.swift; sourceTree = ""; }; @@ -830,12 +821,16 @@ files = ( 8773AF4F27DCB59400739A09 /* FirebaseDatabase in Frameworks */, 87910828283876DD005D7B10 /* Alamofire in Frameworks */, + 8761BDC22BCFE64000E9281A /* CombineMoya in Frameworks */, 876C3B0D2B1045C5002A5132 /* GoogleSignInSwift in Frameworks */, 8773AF5227DCB5D100739A09 /* FSCalendar in Frameworks */, 8773AF4D27DCB59400739A09 /* FirebaseAnalytics in Frameworks */, + 8761BDC82BCFE64000E9281A /* RxMoya in Frameworks */, 876C3B0B2B1045C5002A5132 /* GoogleSignIn in Frameworks */, 87D4DCEB2BA6B04B00BB5AAB /* Lottie in Frameworks */, + 8761BDC42BCFE64000E9281A /* Moya in Frameworks */, 540418171CE07D46B1BD8E3B /* Pods_Project_Timer.framework in Frameworks */, + 8761BDC62BCFE64000E9281A /* ReactiveMoya in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -890,15 +885,15 @@ name = Frameworks; sourceTree = ""; }; - 8708005D2B2C5DF400830B39 /* firebaseValue */ = { + 8708005D2B2C5DF400830B39 /* FirebaseValue */ = { isa = PBXGroup; children = ( - 875C98BD287172A5008F7ADD /* StringValue.swift */, - 875FAE362B1C74AD008F19D2 /* BooleanValue.swift */, - 873731DC2B2E9AA900D7BD9F /* StringArrayValue.swift */, + 875C98BD287172A5008F7ADD /* FirebaseStringValue.swift */, + 875FAE362B1C74AD008F19D2 /* FirebaseBooleanValue.swift */, + 873731DC2B2E9AA900D7BD9F /* FirebaseStringArrayValue.swift */, 873731DE2B2EA2AF00D7BD9F /* FirestoreValue.swift */, ); - path = firebaseValue; + path = FirebaseValue; sourceTree = ""; }; 870800902B2D693800830B39 /* Signin */ = { @@ -953,6 +948,15 @@ path = Password; sourceTree = ""; }; + 871616922C3A146400C4EF25 /* Dailys */ = { + isa = PBXGroup; + children = ( + 871616952C3A149000C4EF25 /* GetDailysUseCase.swift */, + 8716169D2C3A604C00C4EF25 /* PostDailysUseCase.swift */, + ); + path = Dailys; + sourceTree = ""; + }; 87199F422882BC0C0017D01A /* Graph */ = { isa = PBXGroup; children = ( @@ -986,6 +990,20 @@ path = ViewModel; sourceTree = ""; }; + 872210532C300922003B97AD /* Firebase */ = { + isa = PBXGroup; + children = ( + 872210512C3007FD003B97AD /* GetAppVersionUseCase.swift */, + 872210542C30094F003B97AD /* GetServerURLUseCase.swift */, + 872210562C3009DA003B97AD /* GetTiTiFunctionsUseCase.swift */, + 872210582C300A08003B97AD /* GetUpdateHistorysUseCase.swift */, + 8722105A2C300A5C003B97AD /* GetYoutubeLinkUseCase.swift */, + 8722105C2C300A8C003B97AD /* GetSurveysUseCase.swift */, + 871616A52C3A91F900C4EF25 /* GetNotificationUseCase.swift */, + ); + path = Firebase; + sourceTree = ""; + }; 872C0ED9284ADD6800E8E3F2 /* UpdateHistory */ = { isa = PBXGroup; children = ( @@ -1105,6 +1123,31 @@ path = Resource; sourceTree = ""; }; + 874A9DF42C6837BF006D2E19 /* Notification */ = { + isa = PBXGroup; + children = ( + 87FB8D1A2B3C5DF300EA5693 /* NotificationUseCase.swift */, + ); + path = Notification; + sourceTree = ""; + }; + 874A9DF52C68F279006D2E19 /* RecordTimes */ = { + isa = PBXGroup; + children = ( + 871616A12C3A606C00C4EF25 /* GetRecordTimeUseCase.swift */, + 8716169F2C3A605600C4EF25 /* PostRecordTimeUseCase.swift */, + ); + path = RecordTimes; + sourceTree = ""; + }; + 874A9DF62C68F295006D2E19 /* SyncLog */ = { + isa = PBXGroup; + children = ( + 871616A32C3A607700C4EF25 /* GetSyncLogUseCase.swift */, + ); + path = SyncLog; + sourceTree = ""; + }; 874F9C342ABFFDE900675A86 /* LoginSelect */ = { isa = PBXGroup; children = ( @@ -1128,36 +1171,13 @@ path = InteractionView; sourceTree = ""; }; - 875FAE222B1C653A008F19D2 /* DTO */ = { - isa = PBXGroup; - children = ( - 8708005D2B2C5DF400830B39 /* firebaseValue */, - 875FAE292B1C6829008F19D2 /* AppLatestVersionDTO.swift */, - 870800512B2C3A0800830B39 /* ServerURLDTO.swift */, - 8708005E2B2C5F5F00830B39 /* AuthDTO.swift */, - 8708006E2B2CA92C00830B39 /* DailyDTO.swift */, - 87F10938284C589A002E31EA /* FunctionInfo.swift */, - 877D69FB2871C1CB00215B6D /* SurveyInfo.swift */, - 872C0EE5284AF31000E8E3F2 /* UpdateInfo.swift */, - 875C98C62871BB26008F7ADD /* YoutubeLinkInfo.swift */, - 87476DAC28A2794B00FAD273 /* LastestVersionInfo.swift */, - 870800822B2D551700830B39 /* RecordTimesDTO.swift */, - 870800882B2D59EB00830B39 /* SyncLogDTO.swift */, - 873731D42B2E938400D7BD9F /* NotificationDTO.swift */, - ); - path = DTO; - sourceTree = ""; - }; 875FAE232B1C6710008F19D2 /* API */ = { isa = PBXGroup; children = ( - 875FAE242B1C6721008F19D2 /* AppVersionAPI.swift */, - 8708004F2B2C38F900830B39 /* ServerURLAPI.swift */, - 8708005B2B2C4D2D00830B39 /* AuthAPI.swift */, - 8708006A2B2CA57C00830B39 /* DailysAPI.swift */, - 870800782B2D4DE500830B39 /* RecordTimesAPI.swift */, - 870800842B2D593400830B39 /* SyncLogAPI.swift */, - 873731D02B2E92BD00D7BD9F /* NotificationAPI.swift */, + 8761BDBF2BCFE52E00E9281A /* FirebaseAPI.swift */, + 8761BDC92BCFEA7A00E9281A /* AuthAPI.swift */, + 8761BDCB2BCFEC8500E9281A /* DailysAPI.swift */, + 8761BDCD2BCFEFD500E9281A /* API.swift */, ); path = API; sourceTree = ""; @@ -1165,12 +1185,9 @@ 875FAE262B1C678E008F19D2 /* Entity */ = { isa = PBXGroup; children = ( - 87163DC72ACAF2E8008D4072 /* NetworkError.swift */, 878DA1F52AEE617900C60CBF /* SignupInfo.swift */, 875FAE272B1C679D008F19D2 /* AppLatestVersionInfo.swift */, 870800622B2C604100830B39 /* AuthInfo.swift */, - 87D7ED142952B3C100121DE6 /* TestUserSignupInfo.swift */, - 87D7ED162952B69200121DE6 /* TestUserSigninInfo.swift */, 87459705263FF0D700172C0F /* Daily.swift */, 870800702B2CAD9900830B39 /* TaskHistory.swift */, 87A4704726493D4D007B89D6 /* RecordTimes.swift */, @@ -1181,24 +1198,14 @@ 87862E832B2D989A004ED313 /* NotificationInfo.swift */, 87D4DCC62BA52F3800BB5AAB /* ResetPasswordInfo.swift */, 87D4DCE32BA6A18C00BB5AAB /* ChangeCompleteInfo.swift */, + 87476DAC28A2794B00FAD273 /* LastestVersionInfo.swift */, + 872210462C2FF676003B97AD /* SurveyInfo.swift */, + 872210482C2FF6AF003B97AD /* FunctionInfo.swift */, + 8722104A2C2FF6E7003B97AD /* UpdateHistoryInfo.swift */, ); path = Entity; sourceTree = ""; }; - 875FAE2D2B1C7058008F19D2 /* Interface */ = { - isa = PBXGroup; - children = ( - 875FAE2E2B1C7067008F19D2 /* AppLatestVersionRepositoryInterface.swift */, - 870800552B2C3AC600830B39 /* ServerURLRepositoryInterface.swift */, - 870800642B2C623600830B39 /* AuthRepositoryInterface.swift */, - 870800722B2CB11B00830B39 /* DailyRepositoryInterface.swift */, - 8708007C2B2D503600830B39 /* RecordTimesRepositoryInterface.swift */, - 8708008A2B2D5A4400830B39 /* SyncLogRepositoryInterface.swift */, - 873731D62B2E97C100D7BD9F /* NotificationRepositoryInterface.swift */, - ); - path = Interface; - sourceTree = ""; - }; 875FAE322B1C7173008F19D2 /* Present */ = { isa = PBXGroup; children = ( @@ -1220,13 +1227,6 @@ 875FAE332B1C717E008F19D2 /* Interface */ = { isa = PBXGroup; children = ( - 875FAE342B1C718D008F19D2 /* GetLatestVersionUseCaseInterface.swift */, - 870800592B2C3B5800830B39 /* GetServerURLUseCaseInterface.swift */, - 870800682B2C68EF00830B39 /* AuthUseCaseInterface.swift */, - 870800762B2D41EA00830B39 /* DailysUseCaseInterface.swift */, - 870800802B2D54B500830B39 /* RecordTimesUseCaseInterface.swift */, - 8708008E2B2D646C00830B39 /* SyncLogUseCaseInterface.swift */, - 873731DA2B2E983500D7BD9F /* GetNotificationUseCaseInterface.swift */, 87FB8D1C2B3C5F4D00EA5693 /* NotificationUseCaseInterface.swift */, ); path = Interface; @@ -1331,6 +1331,18 @@ path = Setting; sourceTree = ""; }; + 877BDCDF2C390BAE00A50231 /* Auth */ = { + isa = PBXGroup; + children = ( + 877BDCE02C390BCE00A50231 /* SignupUseCase.swift */, + 877BDCE22C390C7900A50231 /* SigninUseCase.swift */, + 877BDCE42C390C8800A50231 /* CheckUsernameExitUseCsae.swift */, + 877BDCE62C390C9300A50231 /* CheckEmailExitUseCase.swift */, + 877BDCE82C390CA800A50231 /* UpdatePasswordUseCase.swift */, + ); + path = Auth; + sourceTree = ""; + }; 87862E852B2D9F8D004ED313 /* Notification */ = { isa = PBXGroup; children = ( @@ -1430,20 +1442,6 @@ path = SyncDailys; sourceTree = ""; }; - 8791081D2838752D005D7B10 /* Network */ = { - isa = PBXGroup; - children = ( - 87910829283877A4005D7B10 /* Network.swift */, - 87163DC92ACAF89B008D4072 /* NetworkResult.swift */, - 875EDA332957E0360037A7EB /* NetworkInterceptor.swift */, - 87D7ED182952BA7200121DE6 /* Extension */, - 8791081E28387537005D7B10 /* NetworkURL.swift */, - 87910822283875CF005D7B10 /* NetworkProtocols.swift */, - 87910820283875C0005D7B10 /* NetworkController.swift */, - ); - path = Network; - sourceTree = ""; - }; 8791C1EA27DCCDF4000D6BA9 /* Timer */ = { isa = PBXGroup; children = ( @@ -1645,7 +1643,6 @@ children = ( 87D4DCBD2BA51EEA00BB5AAB /* ResetPasswordVC.swift */, 87D4DCBF2BA5253600BB5AAB /* ResetPasswordEnvironment.swift */, - 87CBC7DD2BDCDF0400DADB72 /* ResetPasswordRoute.swift */, 87D4DCC32BA52CBF00BB5AAB /* Nickname */, 87D4DCD02BA5A4A300BB5AAB /* Email */, 87D4DCD72BA5C15C00BB5AAB /* Password */, @@ -1667,7 +1664,11 @@ 87D4DCCA2BA5476900BB5AAB /* Request */ = { isa = PBXGroup; children = ( - 87D4DCCB2BA5477400BB5AAB /* ResetPasswordRequest.swift */, + 87D4DCCB2BA5477400BB5AAB /* UpdatePasswordRequest.swift */, + 874B54272C158F890062D0AC /* CheckEmailExitRequest.swift */, + 87D7ED142952B3C100121DE6 /* TestUserSignupRequest.swift */, + 87D7ED162952B69200121DE6 /* TestUserSigninRequest.swift */, + 871616902C39956E00C4EF25 /* CheckUsernameRequest.swift */, ); path = Request; sourceTree = ""; @@ -1675,7 +1676,21 @@ 87D4DCCD2BA548E300BB5AAB /* Response */ = { isa = PBXGroup; children = ( + 8708005D2B2C5DF400830B39 /* FirebaseValue */, 87D4DCCE2BA5492700BB5AAB /* SimpleResponse.swift */, + 87B90B3B2BF4B13D00D6886E /* AppVersionResponse.swift */, + 870800512B2C3A0800830B39 /* ServerURLResponse.swift */, + 8708005E2B2C5F5F00830B39 /* AuthResponse.swift */, + 8708006E2B2CA92C00830B39 /* DailyResponse.swift */, + 870800822B2D551700830B39 /* RecordTimesResponse.swift */, + 870800882B2D59EB00830B39 /* SyncLogResponse.swift */, + 873731D42B2E938400D7BD9F /* NotificationResponse.swift */, + 877D69FB2871C1CB00215B6D /* SurveyResponse.swift */, + 87F10938284C589A002E31EA /* FunctionResponse.swift */, + 872C0EE5284AF31000E8E3F2 /* UpdateHistoryResponse.swift */, + 875C98C62871BB26008F7ADD /* YoutubeLinkResponse.swift */, + 87B90B3E2BF4BC6D00D6886E /* TTErrorResponse.swift */, + 8722104C2C2FFA66003B97AD /* TTResponse.swift */, ); path = Response; sourceTree = ""; @@ -1693,7 +1708,7 @@ 87D4DCD72BA5C15C00BB5AAB /* Password */ = { isa = PBXGroup; children = ( - 87D4DCDC2BA5C1E800BB5AAB /* ResetPasswordRoute.swift */, + 87CBC7DD2BDCDF0400DADB72 /* ResetPasswordRoute.swift */, 87D4DCD82BA5C17900BB5AAB /* ResetPasswordView.swift */, 87D4DCDA2BA5C19C00BB5AAB /* ResetPasswordModel.swift */, ); @@ -1742,15 +1757,6 @@ path = Model; sourceTree = ""; }; - 87D7ED182952BA7200121DE6 /* Extension */ = { - isa = PBXGroup; - children = ( - 87D7ED192952BA8800121DE6 /* JSONParameterEncoder+Extension.swift */, - 878BF7F02955F4600044C079 /* JSONDecoder+Extension.swift */, - ); - path = Extension; - sourceTree = ""; - }; 87D7ED1B2952E3DF00121DE6 /* TestServer */ = { isa = PBXGroup; children = ( @@ -1845,6 +1851,7 @@ 8751C6F928472A8D007FAFC4 /* Collection+Extension.swift */, 875FBE262AC91ED800B28723 /* CGPoint+Extension.swift */, 879BE31D2AC317DB007AAC46 /* CGSize+Extension.swift */, + 8722104E2C2FFD41003B97AD /* JSONDecoder+Extension.swift */, ); path = Foundation; sourceTree = ""; @@ -1882,12 +1889,14 @@ 87F778DC2B196E8F00909511 /* Data */ = { isa = PBXGroup; children = ( - 87D4DCCD2BA548E300BB5AAB /* Response */, - 87D4DCCA2BA5476900BB5AAB /* Request */, - 87F778E12B196F7400909511 /* Repository */, + 87B90B402BF4BFEE00D6886E /* TTProvider.swift */, + 87163DC72ACAF2E8008D4072 /* NetworkError.swift */, + 875EDA332957E0360037A7EB /* NetworkInterceptor.swift */, + 8791081E28387537005D7B10 /* NetworkURL.swift */, 875FAE232B1C6710008F19D2 /* API */, - 875FAE222B1C653A008F19D2 /* DTO */, - 8791081D2838752D005D7B10 /* Network */, + 87F778E12B196F7400909511 /* Repository */, + 87D4DCCA2BA5476900BB5AAB /* Request */, + 87D4DCCD2BA548E300BB5AAB /* Response */, ); path = Data; sourceTree = ""; @@ -1897,7 +1906,6 @@ children = ( 875FAE262B1C678E008F19D2 /* Entity */, 87F778E02B196EDF00909511 /* UseCase */, - 875FAE2D2B1C7058008F19D2 /* Interface */, ); path = Domain; sourceTree = ""; @@ -1905,14 +1913,12 @@ 87F778E02B196EDF00909511 /* UseCase */ = { isa = PBXGroup; children = ( - 875FAE302B1C70C2008F19D2 /* GetLatestVersionUseCase.swift */, - 870800572B2C3B0C00830B39 /* GetServerURLUseCase.swift */, - 870800662B2C67E900830B39 /* AuthUseCase.swift */, - 870800742B2D3C9A00830B39 /* DailysUseCase.swift */, - 8708007E2B2D543500830B39 /* RecordTimesUseCase.swift */, - 8708008C2B2D63D300830B39 /* SyncLogUseCase.swift */, - 873731D82B2E97FE00D7BD9F /* GetNotificationUseCase.swift */, - 87FB8D1A2B3C5DF300EA5693 /* NotificationUseCase.swift */, + 874A9DF42C6837BF006D2E19 /* Notification */, + 872210532C300922003B97AD /* Firebase */, + 877BDCDF2C390BAE00A50231 /* Auth */, + 871616922C3A146400C4EF25 /* Dailys */, + 874A9DF52C68F279006D2E19 /* RecordTimes */, + 874A9DF62C68F295006D2E19 /* SyncLog */, ); path = UseCase; sourceTree = ""; @@ -1920,13 +1926,11 @@ 87F778E12B196F7400909511 /* Repository */ = { isa = PBXGroup; children = ( - 875FAE2B2B1C6B57008F19D2 /* AppLatestVersionRepository.swift */, - 870800532B2C3A5400830B39 /* ServerURLRepository.swift */, - 870800602B2C5FDA00830B39 /* AuthRepository.swift */, - 8708006C2B2CA7AB00830B39 /* DailysRepository.swift */, - 8708007A2B2D4F0800830B39 /* RecordTimesRepository.swift */, - 870800862B2D599800830B39 /* SyncLogRepository.swift */, - 873731D22B2E931800D7BD9F /* NotificationRepository.swift */, + 87B90B392BF4AEF600D6886E /* FirebaseRepository.swift */, + 87FB6B8C2BFE0B3F00CD7A9C /* AuthRepository.swift */, + 874B542B2C1592460062D0AC /* DailysRepository.swift */, + 874B542D2C1595A00062D0AC /* RecordTimesRepository.swift */, + 872210412C2FEE83003B97AD /* SyncLogRepository.swift */, ); path = Repository; sourceTree = ""; @@ -2051,6 +2055,10 @@ 876C3B0A2B1045C5002A5132 /* GoogleSignIn */, 876C3B0C2B1045C5002A5132 /* GoogleSignInSwift */, 87D4DCEA2BA6B04B00BB5AAB /* Lottie */, + 8761BDC12BCFE64000E9281A /* CombineMoya */, + 8761BDC32BCFE64000E9281A /* Moya */, + 8761BDC52BCFE64000E9281A /* ReactiveMoya */, + 8761BDC72BCFE64000E9281A /* RxMoya */, ); productName = Project_Timer; productReference = 93B0851D248DDF2F00E215BD /* TiTi.app */; @@ -2090,6 +2098,7 @@ 87910826283876DD005D7B10 /* XCRemoteSwiftPackageReference "Alamofire" */, 876C3B092B10361E002A5132 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, 87D4DCE92BA6B04B00BB5AAB /* XCRemoteSwiftPackageReference "lottie-ios" */, + 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */, ); productRefGroup = 93B0851E248DDF2F00E215BD /* Products */; projectDirPath = ""; @@ -2210,6 +2219,7 @@ 877911B22A188A3200F0A713 /* SettingSwitchListVC.swift in Sources */, 870800712B2CAD9900830B39 /* TaskHistory.swift in Sources */, 87163DC82ACAF2E8008D4072 /* NetworkError.swift in Sources */, + 872210572C3009DA003B97AD /* GetTiTiFunctionsUseCase.swift in Sources */, 87D5E65028C7460100D53F8D /* MonthSmallVM.swift in Sources */, 879D20742A190DE900D8A420 /* LogSettingVC.swift in Sources */, 8721C6DD296944EE00410D57 /* ChangePrevGraphButton.swift in Sources */, @@ -2217,8 +2227,8 @@ 875A5F792A207BA600679A72 /* NavigationBarInformationButton.swift in Sources */, 879D20772A19101C00D8A420 /* BottomSheetViewController.swift in Sources */, 048D8AD028AABC9E00A2456D /* AddNewTaskHistoryCell.swift in Sources */, - 870800792B2D4DE500830B39 /* RecordTimesAPI.swift in Sources */, 043706312869FB0E00A5D3AA /* StopwatchTimeLabelView.swift in Sources */, + 8722104B2C2FF6E7003B97AD /* UpdateHistoryInfo.swift in Sources */, 04E0DFCB28A926C1004DABBE /* TaskInteractionView.swift in Sources */, 875A5F7B2A20836600679A72 /* HowToUseWidgetVC.swift in Sources */, 87199F512883D0B00017D01A /* TaskInfo.swift in Sources */, @@ -2227,24 +2237,20 @@ 870E117C2A0F7EF000CFA77C /* CalendarWidgetCellData.swift in Sources */, 879BE31E2AC317DB007AAC46 /* CGSize+Extension.swift in Sources */, 87862E822B2D8C22004ED313 /* TTNotificationView.swift in Sources */, - 87910821283875C0005D7B10 /* NetworkController.swift in Sources */, 878BF7ED2955E5430044C079 /* SyncDailysVM.swift in Sources */, 870C70732AD51BEB00024CAC /* PredicateChecker.swift in Sources */, 879BE3242AC42758007AAC46 /* TiTiImage.swift in Sources */, - 8708008D2B2D63D300830B39 /* SyncLogUseCase.swift in Sources */, 87EA022F2B9BF927003439F2 /* UIViewControllerPreview.swift in Sources */, 87EA02312B9BF941003439F2 /* UIViewPreview.swift in Sources */, + 87B90B3A2BF4AEF600D6886E /* FirebaseRepository.swift in Sources */, 873C197A28D04B5B00E02ADC /* DayOfWeekText.swift in Sources */, - 870800852B2D593400830B39 /* SyncLogAPI.swift in Sources */, - 87163DCA2ACAF89B008D4072 /* NetworkResult.swift in Sources */, 874F9C2B2ABFF51700675A86 /* SigninSelectView.swift in Sources */, 871C1A0328519CC200BDAE02 /* SettingDevInfoCell.swift in Sources */, 87ED9ABF28D16FC200186677 /* TasksCircularProgressDTO.swift in Sources */, 87D4DCD62BA5A7B100BB5AAB /* ResetPasswordEmailRoute.swift in Sources */, 049BBA9828AB3D94005BAB1B /* ModifyFinishButton.swift in Sources */, - 873731D12B2E92BD00D7BD9F /* NotificationAPI.swift in Sources */, - 873731D52B2E938400D7BD9F /* NotificationDTO.swift in Sources */, - 8708006D2B2CA7AB00830B39 /* DailysRepository.swift in Sources */, + 873731D52B2E938400D7BD9F /* NotificationResponse.swift in Sources */, + 874B54282C158F890062D0AC /* CheckEmailExitRequest.swift in Sources */, 8758E4F528C7124900A99484 /* MonthSmallView.swift in Sources */, 87A722A828CCB95C000DA304 /* MonthVM.swift in Sources */, 87A8BC3B288D1436007ED793 /* LogVC.swift in Sources */, @@ -2252,7 +2258,6 @@ 879BE3262AC42919007AAC46 /* SigninInputTextfield.swift in Sources */, 049BBA9E28AB76B8005BAB1B /* TaskInteractionViewPlaceholder.swift in Sources */, 87A722A628CCB928000DA304 /* LogHomeTaskCellView.swift in Sources */, - 870800772B2D41EA00830B39 /* DailysUseCaseInterface.swift in Sources */, 875C98C3287176E4008F7ADD /* FunctionsActionDelegate.swift in Sources */, 8765234A28C7709700487BFB /* WeekSmallView.swift in Sources */, 8765235128C79C4400487BFB /* TotalView.swift in Sources */, @@ -2263,33 +2268,31 @@ 87306D592B260E09001B7C14 /* Localized.swift in Sources */, 879D207B2A19B91C00D8A420 /* ColorButton.swift in Sources */, 877911BA2A1891B100F0A713 /* SettingSwitchListVM.swift in Sources */, - 875FAE372B1C74AD008F19D2 /* BooleanValue.swift in Sources */, + 875FAE372B1C74AD008F19D2 /* FirebaseBooleanValue.swift in Sources */, 87BEBEE9281C17000095CD29 /* RecordsManager.swift in Sources */, 87FB8D1D2B3C5F4D00EA5693 /* NotificationUseCaseInterface.swift in Sources */, 87A48BCD27DF182400F46D0F /* SubjectCell.swift in Sources */, 04172E982885453F00F962F2 /* MotionDetector.swift in Sources */, 87F10936284C47A1002E31EA /* SettingTiTiLabVM.swift in Sources */, 87B7A53C2AC02202002AFDFE /* SigninSelectRoute.swift in Sources */, - 873731DD2B2E9AA900D7BD9F /* StringArrayValue.swift in Sources */, + 873731DD2B2E9AA900D7BD9F /* FirebaseStringArrayValue.swift in Sources */, 8760FB0C2A1DBB490068CEF5 /* Widget+Extentions.swift in Sources */, + 874B542E2C1595A00062D0AC /* RecordTimesRepository.swift in Sources */, 879BE32C2AC68EC7007AAC46 /* PortraitVC.swift in Sources */, - 875FAE2F2B1C7067008F19D2 /* AppLatestVersionRepositoryInterface.swift in Sources */, 879053FF29558EF4008B9258 /* SyncUserStatusView.swift in Sources */, 875FBE272AC91ED800B28723 /* CGPoint+Extension.swift in Sources */, - 870800542B2C3A5400830B39 /* ServerURLRepository.swift in Sources */, 875EDA342957E0360037A7EB /* NetworkInterceptor.swift in Sources */, 870E11752A0E226D00CFA77C /* CalendarWidgetData.swift in Sources */, - 870800752B2D3C9A00830B39 /* DailysUseCase.swift in Sources */, - 870800612B2C5FDA00830B39 /* AuthRepository.swift in Sources */, 87CEDD3D28F5338B007ACF6E /* ColorSelectorVC.swift in Sources */, - 878BF7F12955F4600044C079 /* JSONDecoder+Extension.swift in Sources */, 8706C32C2AEF864000F7C842 /* TTSignupTitleView.swift in Sources */, 877911BC2A18922400F0A713 /* SettingListCellInfo.swift in Sources */, + 871616A02C3A605600C4EF25 /* PostRecordTimeUseCase.swift in Sources */, 8791081F28387537005D7B10 /* NetworkURL.swift in Sources */, - 873731DB2B2E983500D7BD9F /* GetNotificationUseCaseInterface.swift in Sources */, 87D83E852B285D4D003C40AE /* SettingLanguageVC.swift in Sources */, 873C197628D041DE00E02ADC /* DailyView.swift in Sources */, 87D4DCCF2BA5492700BB5AAB /* SimpleResponse.swift in Sources */, + 87B90B3C2BF4B13D00D6886E /* AppVersionResponse.swift in Sources */, + 871616912C39956E00C4EF25 /* CheckUsernameRequest.swift in Sources */, 875FAE282B1C679D008F19D2 /* AppLatestVersionInfo.swift in Sources */, 87DC6A4928D0104300455A06 /* WeekVM.swift in Sources */, 048D8AC628AA1B7700A2456D /* AddHistoryCell.swift in Sources */, @@ -2301,19 +2304,21 @@ 878DA1F62AEE617900C60CBF /* SignupInfo.swift in Sources */, 879BE3202AC402A8007AAC46 /* SignupSigninVC.swift in Sources */, 048D8AD328AAC5CF00A2456D /* TaskCreateInteractionView.swift in Sources */, - 870800832B2D551700830B39 /* RecordTimesDTO.swift in Sources */, + 870800832B2D551700830B39 /* RecordTimesResponse.swift in Sources */, 8757AA3B290511AB00D97517 /* TaskSelectVM.swift in Sources */, 87FD9FA72998D0BD00D9B0FF /* TimerStopwatchAttributes.swift in Sources */, 04573A9B2877FDDA008F8D44 /* CountdownTimeLabelVM.swift in Sources */, 87306D5D2B26CB5C001B7C14 /* Typographys.swift in Sources */, + 8716169E2C3A604C00C4EF25 /* PostDailysUseCase.swift in Sources */, 87306D612B26CBBC001B7C14 /* Icons.swift in Sources */, 87199F4B2883C6D80017D01A /* StandardDailyTaskCell.swift in Sources */, + 871616A42C3A607700C4EF25 /* GetSyncLogUseCase.swift in Sources */, 048D8ACD28AA608900A2456D /* PopupSelectDateVC.swift in Sources */, 87035DF7282225C800055378 /* Protocols.swift in Sources */, 87DB923E2AC2D06C00FE6453 /* View+Extension.swift in Sources */, 043706272869D58C00A5D3AA /* TimerTimeLabelView.swift in Sources */, 874F9C312ABFF81300675A86 /* EmailSigninButton.swift in Sources */, - 870800692B2C68EF00830B39 /* AuthUseCaseInterface.swift in Sources */, + 871616962C3A149000C4EF25 /* GetDailysUseCase.swift in Sources */, 878DA8252B0C78D8001E924E /* SignupNicknameRoute.swift in Sources */, 870F90E52AEFFA9300854DDB /* SignupPasswordModel.swift in Sources */, 87D4DCD42BA5A53F00BB5AAB /* ResetPasswordEmailModel.swift in Sources */, @@ -2321,67 +2326,66 @@ 877911B82A18903000F0A713 /* SettingListCell.swift in Sources */, 870F90E32AEFF7FC00854DDB /* SignupPasswordView.swift in Sources */, 87BEBEEB281C19CA0095CD29 /* StopwatchVM.swift in Sources */, - 87F1093A284C589A002E31EA /* FunctionInfo.swift in Sources */, + 87F1093A284C589A002E31EA /* FunctionResponse.swift in Sources */, 875AA59C26494365005D15D6 /* TaskSelectVC.swift in Sources */, - 875C98C72871BB26008F7ADD /* YoutubeLinkInfo.swift in Sources */, + 875C98C72871BB26008F7ADD /* YoutubeLinkResponse.swift in Sources */, 87D4DCE22BA6A12B00BB5AAB /* ResetPasswordCompleteModel.swift in Sources */, 04B5293B28B4E40500906C86 /* PopupEditTaskNameVC.swift in Sources */, 8765234828C76FFE00487BFB /* WeekSmallVM.swift in Sources */, 87A48BC927DF026800F46D0F /* Int+Extension.swift in Sources */, 872C0EDE284AE52800E8E3F2 /* SettingFunctionsListVC.swift in Sources */, - 8708007D2B2D503600830B39 /* RecordTimesRepositoryInterface.swift in Sources */, - 870800672B2C67E900830B39 /* AuthUseCase.swift in Sources */, 87D1250128771AAD00018658 /* Language.swift in Sources */, 87CAC06228B8711D0036CF24 /* FirebaseEvent.swift in Sources */, 879D20792A19B3D300D8A420 /* ThemeColorSelectorView.swift in Sources */, 871AB69B2967C9C500AFED1C /* TimeTableView.swift in Sources */, 87E5C70F2AE0C0E500BE46B0 /* TTSignupTextFieldView.swift in Sources */, 87AEF671289D23400018FCC8 /* UITabBarController+Extension.swift in Sources */, - 8791082A283877A4005D7B10 /* Network.swift in Sources */, 87199F5C28840E970017D01A /* TasksCircularProgressView.swift in Sources */, 87DC6A4B28D010A400455A06 /* WeekTime.swift in Sources */, 87BE88E72AD425BE0010A84A /* SigninTextFieldView.swift in Sources */, 87E5C70D2AE0268C00BE46B0 /* SignupEmailView.swift in Sources */, + 871616A62C3A91F900C4EF25 /* GetNotificationUseCase.swift in Sources */, 049BBA9A28AB5747005BAB1B /* TaskModifyInteractionView.swift in Sources */, 87A8CD272AF0C4B600D4C1D7 /* OverlayShowButtonForSecureFieldView.swift in Sources */, - 870800502B2C38F900830B39 /* ServerURLAPI.swift in Sources */, 870E85012AD67E46000511BD /* KeyboardResponder.swift in Sources */, - 870800872B2D599800830B39 /* SyncLogRepository.swift in Sources */, + 877BDCE92C390CA800A50231 /* UpdatePasswordUseCase.swift in Sources */, 87A48BCB27DF112B00F46D0F /* LogHomeVM.swift in Sources */, - 87D7ED172952B69200121DE6 /* TestUserSigninInfo.swift in Sources */, + 87D7ED172952B69200121DE6 /* TestUserSigninRequest.swift in Sources */, 87D4DCC02BA5253600BB5AAB /* ResetPasswordEnvironment.swift in Sources */, 8706C3322AEF8A0300F7C842 /* TTSignupNextButtonForMac.swift in Sources */, 87306D532B260969001B7C14 /* TLRen.swift in Sources */, - 8708008F2B2D646C00830B39 /* SyncLogUseCaseInterface.swift in Sources */, 87199F5E28842F0E0017D01A /* CheckGraphButton.swift in Sources */, - 870800652B2C623600830B39 /* AuthRepositoryInterface.swift in Sources */, 87F10930284C4337002E31EA /* TiTiLabHeaderView.swift in Sources */, 879D20812A19E44B00D8A420 /* TargetTimeView.swift in Sources */, 87A4704826493D4D007B89D6 /* RecordTimes.swift in Sources */, 87A8CD252AF0C37200D4C1D7 /* TTSignupSecureFieldView.swift in Sources */, 872C0EE3284AF26A00E8E3F2 /* SettingUpdateHistoryVM.swift in Sources */, + 8761BDCE2BCFEFD500E9281A /* API.swift in Sources */, 87EFD6832AC12C3800C422B1 /* SigninSignupEnvironment.swift in Sources */, 93A892B124C14D4700F89180 /* CircularProgressView.swift in Sources */, 8791C1F427DCD120000D6BA9 /* UserDefaultsManager.swift in Sources */, - 873731D72B2E97C100D7BD9F /* NotificationRepositoryInterface.swift in Sources */, 8765234F28C7964500487BFB /* TotalVM.swift in Sources */, 878899852894F09600B7F378 /* WeekTimelineView.swift in Sources */, + 872210472C2FF676003B97AD /* SurveyInfo.swift in Sources */, 87D83E8C2B29703A003C40AE /* SettingLanguageVM.swift in Sources */, 87F1093B284C589A002E31EA /* SettingFunctionsListVM.swift in Sources */, - 8708006F2B2CA92C00830B39 /* DailyDTO.swift in Sources */, + 8708006F2B2CA92C00830B39 /* DailyResponse.swift in Sources */, 8788997C2894F00000B7F378 /* LogWeekVM.swift in Sources */, + 8761BDCA2BCFEA7A00E9281A /* AuthAPI.swift in Sources */, 87EFD6812AC115DB00C422B1 /* SigninSignupVC.swift in Sources */, 873C197828D044CC00E02ADC /* DailyVM.swift in Sources */, 87BF666C28F80EA500CD6F19 /* NormalTimeLabelVM.swift in Sources */, 87A8CD292AF0C5CB00D4C1D7 /* OverlayRemoveButtonForTextFieldView.swift in Sources */, 8751C6F628472133007FAFC4 /* SettingCellInfo.swift in Sources */, 87D4DCC72BA52F3800BB5AAB /* ResetPasswordInfo.swift in Sources */, + 87B90B412BF4BFEE00D6886E /* TTProvider.swift in Sources */, 8750082D2905998200E27B4A /* TargetTimeSettingPopupVC.swift in Sources */, 8760FCB929541BE3000BCCD1 /* KeyChain.swift in Sources */, 87D5E65328C7477100D53F8D /* MonthTime.swift in Sources */, 87D83E8A2B2964EC003C40AE /* SettingLanguageListView.swift in Sources */, + 871616A22C3A606C00C4EF25 /* GetRecordTimeUseCase.swift in Sources */, 87D4DCD92BA5C17900BB5AAB /* ResetPasswordView.swift in Sources */, - 87D7ED152952B3C100121DE6 /* TestUserSignupInfo.swift in Sources */, + 87D7ED152952B3C100121DE6 /* TestUserSignupRequest.swift in Sources */, 878DA8232B0C6B1E001E924E /* SigninSelectModel.swift in Sources */, 04504C642864C7F500CA4C69 /* BaseTimeLabelView.swift in Sources */, 87D83E882B296069003C40AE /* TTSettingSelectableCell.swift in Sources */, @@ -2394,19 +2398,21 @@ 878813E32A2084F5000ED2C1 /* CloseButton.swift in Sources */, 87A48BC727DEF0C200F46D0F /* Date+Extension.swift in Sources */, 871AB699296709C100AFED1C /* TimeTableDailyGraphView.swift in Sources */, + 872210522C3007FD003B97AD /* GetAppVersionUseCase.swift in Sources */, 87DC6A4728D00DF400455A06 /* WeekView.swift in Sources */, 873731DF2B2EA2B000D7BD9F /* FirestoreValue.swift in Sources */, 8706C32E2AEF878D00F7C842 /* TTSignupTextFieldUnderlineView.swift in Sources */, 87199F442882BC430017D01A /* StandardDailyGraphView.swift in Sources */, 93B08521248DDF2F00E215BD /* AppDelegate.swift in Sources */, - 870800522B2C3A0800830B39 /* ServerURLDTO.swift in Sources */, + 877BDCE32C390C7900A50231 /* SigninUseCase.swift in Sources */, + 874B542C2C1592460062D0AC /* DailysRepository.swift in Sources */, + 870800522B2C3A0800830B39 /* ServerURLResponse.swift in Sources */, 8791C1F227DCD050000D6BA9 /* Notification+Extension.swift in Sources */, 87F771BF2984101700BF1907 /* Todolist.swift in Sources */, 878BF7EF2955E73C0044C079 /* SyncLog.swift in Sources */, 87306D512B26086D001B7C14 /* TLRko.swift in Sources */, 878431AD27F6F461000A98B3 /* TodolistVM.swift in Sources */, 878DA1F82AEE68DA00C60CBF /* SignupEmailModel.swift in Sources */, - 870800732B2CB11B00830B39 /* DailyRepositoryInterface.swift in Sources */, 04FA75D8286F2AB900BAE2B2 /* Fonts.swift in Sources */, 87862E872B2D9FA1004ED313 /* NotificationVC.swift in Sources */, 8751C6F82847234A007FAFC4 /* SettingVM.swift in Sources */, @@ -2417,39 +2423,40 @@ 8791082F28387D1F005D7B10 /* String+Extension.swift in Sources */, 87D4DE112A0F83A500993C5C /* CalendarWidgetTaskData.swift in Sources */, 87459704263FEF6B00172C0F /* TimerVC.swift in Sources */, + 87B90B3F2BF4BC6D00D6886E /* TTErrorResponse.swift in Sources */, + 8722104F2C2FFD41003B97AD /* JSONDecoder+Extension.swift in Sources */, 87A4704A26493D6E007B89D6 /* StaticCircularProgressView.swift in Sources */, 879E849C29C83D5100D65F48 /* RoundedShape.swift in Sources */, 87199F582883F2E00017D01A /* TimelineVM.swift in Sources */, - 870800562B2C3AC600830B39 /* ServerURLRepositoryInterface.swift in Sources */, + 8761BDC02BCFE52E00E9281A /* FirebaseAPI.swift in Sources */, 877036CA29CD7B3B0078A30C /* TaskManager.swift in Sources */, + 8761BDCC2BCFEC8500E9281A /* DailysAPI.swift in Sources */, 878DA8212B0C62E1001E924E /* SignupNicknameView.swift in Sources */, 048D8ACB28AA49F800A2456D /* PopupEditHistoryVC.swift in Sources */, 878DA81F2B0C62A9001E924E /* SignupNicknameModel.swift in Sources */, 87306D572B260AB8001B7C14 /* TLRkey.swift in Sources */, 043706332869FB9F00A5D3AA /* StopwatchTimeLabelVM.swift in Sources */, 87BEBEEF281CD7EC0095CD29 /* UIViewController+Extension.swift in Sources */, - 8708005C2B2C4D2D00830B39 /* AuthAPI.swift in Sources */, 87D4C95A28950B4E008ECAA4 /* WeekDailysData.swift in Sources */, 87199F462883018C0017D01A /* TimelineDailyGraphView.swift in Sources */, 87476DAD28A2794B00FAD273 /* LastestVersionInfo.swift in Sources */, - 870800812B2D54B500830B39 /* RecordTimesUseCaseInterface.swift in Sources */, - 8708005A2B2C3B5800830B39 /* GetServerURLUseCaseInterface.swift in Sources */, 87459706263FF0D700172C0F /* Daily.swift in Sources */, 87FB8D1B2B3C5DF400EA5693 /* NotificationUseCase.swift in Sources */, 8757AA3D290511FF00D97517 /* Task.swift in Sources */, 04E0DFCD28A94460004DABBE /* PaddingLabel.swift in Sources */, 87405D6628F5869D00576D2C /* ColorofTextSelectorVC.swift in Sources */, + 872210492C2FF6AF003B97AD /* FunctionInfo.swift in Sources */, 872C0EDB284ADD8300E8E3F2 /* SettingUpdateHistoryVC.swift in Sources */, 87F1093C284C589A002E31EA /* FunctionInfoCell.swift in Sources */, 87D4DCE42BA6A18C00BB5AAB /* ChangeCompleteInfo.swift in Sources */, + 877BDCE12C390BCE00A50231 /* SignupUseCase.swift in Sources */, 8788997A2894EFEE00B7F378 /* LogWeekVC.swift in Sources */, 872C0EE1284AE57200E8E3F2 /* SettingTiTiLabVC.swift in Sources */, 875EDA362957F9510037A7EB /* LoadingIndicator.swift in Sources */, - 872C0EE6284AF31000E8E3F2 /* UpdateInfo.swift in Sources */, + 872C0EE6284AF31000E8E3F2 /* UpdateHistoryResponse.swift in Sources */, 87BF666A28F80E9400CD6F19 /* NormalTimeLabelView.swift in Sources */, 87E6004B28426EBF008D17B9 /* SettingVC.swift in Sources */, 93B08523248DDF2F00E215BD /* SceneDelegate.swift in Sources */, - 87D7ED1A2952BA8800121DE6 /* JSONParameterEncoder+Extension.swift in Sources */, 875C98CB2871C0A7008F7ADD /* UIImage+Extension.swift in Sources */, 87459708263FF0F000172C0F /* Storage.swift in Sources */, 8788997F2894F03300B7F378 /* StandardWeekGraphView.swift in Sources */, @@ -2459,35 +2466,32 @@ 876E27762AC1CD2A0054250D /* Infos.swift in Sources */, 049BBA9C28AB58D4005BAB1B /* InteractionLeftTitleLabel.swift in Sources */, 871AB69D2967C9D100AFED1C /* TimeTableVM.swift in Sources */, - 8708006B2B2CA57C00830B39 /* DailysAPI.swift in Sources */, - 870800582B2C3B0C00830B39 /* GetServerURLUseCase.swift in Sources */, + 872210422C2FEE83003B97AD /* SyncLogRepository.swift in Sources */, 87D4DCD22BA5A4C400BB5AAB /* ResetPasswordEmailView.swift in Sources */, 878813E52A209BA0000ED2C1 /* HowToAddWidgetVC.swift in Sources */, - 8708007B2B2D4F0800830B39 /* RecordTimesRepository.swift in Sources */, + 8722105D2C300A8C003B97AD /* GetSurveysUseCase.swift in Sources */, 8765234C28C7948700487BFB /* TotalTime.swift in Sources */, 87A7F5D4267270F800F69EBA /* Todo.swift in Sources */, 879D207F2A19D40400D8A420 /* Updateable.swift in Sources */, 87AE748429062ACA00FA0A60 /* TimeSelectorPopupVC.swift in Sources */, - 875C98BE287172A5008F7ADD /* StringValue.swift in Sources */, + 875C98BE287172A5008F7ADD /* FirebaseStringValue.swift in Sources */, 87024B102AE154630095CCB4 /* SignupEmailRoute.swift in Sources */, + 8722104D2C2FFA66003B97AD /* TTResponse.swift in Sources */, 04573A992877FD78008F8D44 /* CountdownTimeLabelView.swift in Sources */, 87BEBEED281C282D0095CD29 /* Times.swift in Sources */, 879BE3222AC40444007AAC46 /* SignupSigninVM.swift in Sources */, 8791C1F627DCE703000D6BA9 /* UIView+Extension.swift in Sources */, 87D4DCC92BA52FC800BB5AAB /* ResetPasswordNicknameRoute.swift in Sources */, + 87FB6B8D2BFE0B3F00CD7A9C /* AuthRepository.swift in Sources */, 87D4DCC22BA5298B00BB5AAB /* ResetPasswordNicknameView.swift in Sources */, 87C2F97B28A6BFC700F44D98 /* ModifyRecordVC.swift in Sources */, - 8708008B2B2D5A4400830B39 /* SyncLogRepositoryInterface.swift in Sources */, - 873731D92B2E97FE00D7BD9F /* GetNotificationUseCase.swift in Sources */, - 87D4DCCC2BA5477400BB5AAB /* ResetPasswordRequest.swift in Sources */, + 87D4DCCC2BA5477400BB5AAB /* UpdatePasswordRequest.swift in Sources */, 879A2BA8284746A500B69DA7 /* SettingFooterView.swift in Sources */, 04E0DFC328A9031A004DABBE /* ModifyRecordVM.swift in Sources */, - 875FAE352B1C718D008F19D2 /* GetLatestVersionUseCaseInterface.swift in Sources */, 8769349727E1BBAF00D33F51 /* TodoCell.swift in Sources */, 0437062D2869EC2200A5D3AA /* TimerTimeLabelVM.swift in Sources */, + 872210592C300A08003B97AD /* GetUpdateHistorysUseCase.swift in Sources */, 878899882894F0B900B7F378 /* WeekTimelineVM.swift in Sources */, - 87910823283875CF005D7B10 /* NetworkProtocols.swift in Sources */, - 875FAE252B1C6721008F19D2 /* AppVersionAPI.swift in Sources */, 04F0D2B9286607A7007ED596 /* BaseSingleTimeLabelVM.swift in Sources */, 8751C6F428472066007FAFC4 /* SettingCell.swift in Sources */, 87035DF2282201A500055378 /* TimerVM.swift in Sources */, @@ -2496,11 +2500,10 @@ 87D4DCBE2BA51EEA00BB5AAB /* ResetPasswordVC.swift in Sources */, 879E849F29C8400700D65F48 /* TimeLabelData.swift in Sources */, 04FA75D3286EE4D900BAE2B2 /* Color+Extension.swift in Sources */, - 870800892B2D59EB00830B39 /* SyncLogDTO.swift in Sources */, + 870800892B2D59EB00830B39 /* SyncLogResponse.swift in Sources */, 8760FCBB29553F06000BCCD1 /* SyncDailysVC.swift in Sources */, 873977EB288D3FAA0025EE73 /* LogDailyVM.swift in Sources */, 87D3CF05288BAA1300ED33B7 /* ProgressDailyTaskCell.swift in Sources */, - 875FAE312B1C70C2008F19D2 /* GetLatestVersionUseCase.swift in Sources */, 87199F48288303B60017D01A /* TasksProgressDailyGraphView.swift in Sources */, 87585AE22955A49F007E9139 /* SyncDeviceStatusView.swift in Sources */, 87789E44288BC1FC00759C01 /* TimeView.swift in Sources */, @@ -2511,27 +2514,27 @@ 870C70712AD4ECB700024CAC /* SigninRoute.swift in Sources */, 879A2BA6284741A500B69DA7 /* SettingHeaderView.swift in Sources */, 8721C6DB296943C500410D57 /* ChangeNextGraphButton.swift in Sources */, - 873731D32B2E931800D7BD9F /* NotificationRepository.swift in Sources */, - 877D69FC2871C1CB00215B6D /* SurveyInfo.swift in Sources */, + 877D69FC2871C1CB00215B6D /* SurveyResponse.swift in Sources */, 874F9C2F2ABFF7CF00675A86 /* GoogleSigninButton.swift in Sources */, 87199F552883EB160017D01A /* TimelineView.swift in Sources */, 87306D552B2609CE001B7C14 /* TLRzh.swift in Sources */, 87D4DCE82BA6A8AA00BB5AAB /* TTBottomRoundButtonView.swift in Sources */, - 875FAE2C2B1C6B57008F19D2 /* AppLatestVersionRepository.swift in Sources */, 04504C602864AC3C00CA4C69 /* BaseTimeLabelVM.swift in Sources */, + 8722105B2C300A5C003B97AD /* GetYoutubeLinkUseCase.swift in Sources */, 8772E91626705EE100A191BF /* TodolistVC.swift in Sources */, 87B539AB299BB710001E354C /* Versions.swift in Sources */, 87862E892B2DBBDA004ED313 /* PopupVC.swift in Sources */, 8760FB112A1DED3F0068CEF5 /* CalendarWidgetView.swift in Sources */, 875C98C92871BFCF008F7ADD /* UserDefaults+Extension.swift in Sources */, + 877BDCE52C390C8800A50231 /* CheckUsernameExitUseCsae.swift in Sources */, 87D4DCE62BA6A2AB00BB5AAB /* TTChangeCompleteTitleView.swift in Sources */, 874F9C332ABFFDDF00675A86 /* SigninView.swift in Sources */, 87D4DCDB2BA5C19C00BB5AAB /* ResetPasswordModel.swift in Sources */, 87DE1177268AC9AD0012F043 /* DailyManager.swift in Sources */, - 8708007F2B2D543500830B39 /* RecordTimesUseCase.swift in Sources */, - 8708005F2B2C5F5F00830B39 /* AuthDTO.swift in Sources */, - 875FAE2A2B1C6829008F19D2 /* AppLatestVersionDTO.swift in Sources */, + 877BDCE72C390C9300A50231 /* CheckEmailExitUseCase.swift in Sources */, + 8708005F2B2C5F5F00830B39 /* AuthResponse.swift in Sources */, 8721C6D72969123E00410D57 /* IOUsecase.swift in Sources */, + 872210552C30094F003B97AD /* GetServerURLUseCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2671,11 +2674,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Project_Timer/Project_TimerDevelop.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 2C96RNDN63; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = 2C96RNDN63; "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; INFOPLIST_FILE = Project_Timer/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; @@ -2687,7 +2689,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_ID)"; PRODUCT_NAME = "$(APP_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = profile_grin_dev; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_VERSION = 5.0; @@ -3001,6 +3002,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Moya/Moya.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 15.0.3; + }; + }; 876C3B092B10361E002A5132 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/google/GoogleSignIn-iOS"; @@ -3044,6 +3053,26 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 8761BDC12BCFE64000E9281A /* CombineMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */; + productName = CombineMoya; + }; + 8761BDC32BCFE64000E9281A /* Moya */ = { + isa = XCSwiftPackageProductDependency; + package = 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */; + productName = Moya; + }; + 8761BDC52BCFE64000E9281A /* ReactiveMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */; + productName = ReactiveMoya; + }; + 8761BDC72BCFE64000E9281A /* RxMoya */ = { + isa = XCSwiftPackageProductDependency; + package = 8761BDBD2BCFE47000E9281A /* XCRemoteSwiftPackageReference "Moya" */; + productName = RxMoya; + }; 876C3B0A2B1045C5002A5132 /* GoogleSignIn */ = { isa = XCSwiftPackageProductDependency; package = 876C3B092B10361E002A5132 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; diff --git a/Project_Timer/AppDelegate.swift b/Project_Timer/AppDelegate.swift index 5090d69b..3f887feb 100644 --- a/Project_Timer/AppDelegate.swift +++ b/Project_Timer/AppDelegate.swift @@ -12,6 +12,8 @@ import FirebaseAnalytics import GoogleMobileAds import WidgetKit import GoogleSignIn +import Moya +import Combine @UIApplicationMain final class AppDelegate: UIResponder, UIApplicationDelegate { @@ -21,6 +23,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { } // 화면 회전을 제어할 변수 선언 var shouldSupportPortraitOrientation = false + // Combine binding + private var cancellables = Set() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { self.checkLatestVersion(isLaunch: true) @@ -101,17 +105,27 @@ extension AppDelegate: UNUserNotificationCenterDelegate { // MARK: Configure extension AppDelegate { + /// 최신버전 체크 private func checkLatestVersion(isLaunch: Bool) { - /// 최신버전 체크로직 - let getLatestVersionUseCase = GetLatestVersionUseCase(repository: AppLatestVersionRepository()) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getAppVersionUseCase = GetAppVersionUseCase(repository: repository) - getLatestVersionUseCase.getLatestVersion { result in - switch result { - case .success(let latestVersionInfo): - let storeVersion = latestVersionInfo.latestVersion + getAppVersionUseCase.execute() + .sink { [weak self] completion in + if case .failure = completion { + // MARK: 버전 불러오기 실패 Alert 표시 + let title = Localized.string(.App_Popup_FetchVersionErrorTitle) + let text = Localized.string(.App_Popup_FetchVersionErrorDesc) + let ok = UIAlertAction(title: Localized.string(.Common_Text_OK), style: .default) + self?.showAlert(title: title, text: text, actions: [ok]) + } + } receiveValue: { [weak self] appLatestVersionInfo in + let storeVersion = appLatestVersionInfo.latestVersion guard storeVersion.compare(String.currentVersion, options: .numeric) == .orderedDescending else { return } - if latestVersionInfo.forced == true { + if appLatestVersionInfo.forced == true { // MARK: 강제 업데이트 필요 Alert 표시 let title = Localized.string(.Update_Popup_HardUpdateTitle) let text = Localized.string(.Update_Popup_HardUpdateDesc) @@ -124,7 +138,7 @@ extension AppDelegate { } } } - self.showAlert(title: title, text: text, actions: [ok]) + self?.showAlert(title: title, text: text, actions: [ok]) } else if isLaunch == true && UserDefaultsManager.get(forKey: .updatePushable) as? Bool ?? true { // MARK: 업데이트 Alert 표시 let title = Localized.string(.Update_Pupup_SoftUpdateTitle) @@ -137,13 +151,10 @@ extension AppDelegate { UIApplication.shared.open(url, options: [:]) } } - self.showAlert(title: title, text: text, actions: [pass, update]) + self?.showAlert(title: title, text: text, actions: [pass, update]) } - - case .failure(let networkError): - print(networkError.alertMessage) } - } + .store(in: &self.cancellables) } private func showAlert(title: String, text: String?, actions: [UIAlertAction]) { @@ -217,28 +228,27 @@ extension AppDelegate { } private func checkNotification() { - let getNotficationUseCase = GetNotificationUseCase(repository: NotificationRepository()) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getNotificationUseCase = GetNotificationUseCase(repository: repository) let notificationUseCase = NotificationUseCase() - getNotficationUseCase.getNoti { result in - switch result { - case .success(let noti): - guard let noti = noti else { return } + getNotificationUseCase.execute() + .sink { completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + } + } receiveValue: { notificationInfo in + guard let notificationInfo = notificationInfo else { return } guard notificationUseCase.isShowNotification() else { return } DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - let notificationVC = NotificationVC(noti: noti, notificationUseCase: notificationUseCase) + let notificationVC = NotificationVC(noti: notificationInfo, notificationUseCase: notificationUseCase) SceneDelegate.sharedWindow?.rootViewController?.present(notificationVC, animated: true) } - case .failure(let networkError): - switch networkError { - case .NOTFOUND(_): - return - default: - print(networkError.alertMessage) - } } - } + .store(in: &self.cancellables) } private func updateToLastestVersion() { diff --git a/Project_Timer/Data/Network/Extension/JSONDecoder+Extension.swift b/Project_Timer/Core/Extension/Foundation/JSONDecoder+Extension.swift similarity index 74% rename from Project_Timer/Data/Network/Extension/JSONDecoder+Extension.swift rename to Project_Timer/Core/Extension/Foundation/JSONDecoder+Extension.swift index 04b25ce6..d3d38c20 100644 --- a/Project_Timer/Data/Network/Extension/JSONDecoder+Extension.swift +++ b/Project_Timer/Core/Extension/Foundation/JSONDecoder+Extension.swift @@ -2,8 +2,8 @@ // JSONDecoder+Extension.swift // Project_Timer // -// Created by Kang Minsang on 2022/12/23. -// Copyright © 2022 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation diff --git a/Project_Timer/Core/Localize/TLRen.swift b/Project_Timer/Core/Localize/TLRen.swift index 677d5a82..dcb0f974 100644 --- a/Project_Timer/Core/Localize/TLRen.swift +++ b/Project_Timer/Core/Localize/TLRen.swift @@ -31,6 +31,9 @@ struct TLRen { case .Common_Popup_Warning: value = "Warning" case .Common_Popup_Inform: value = "Inform" + case .App_Popup_FetchVersionErrorTitle: value = "Failed to fetch the latest version information" + case .App_Popup_FetchVersionErrorDesc: value = "If the issue persists, please contact support." + case .System_Noti_StopwatchHourPassed: value = "{}hours passed." case .System_Noti_TimerFinished: value = "Timer finished!" case .System_Noti_Timer5Left: value = "5 minutes left" diff --git a/Project_Timer/Core/Localize/TLRkey.swift b/Project_Timer/Core/Localize/TLRkey.swift index 33bbe5a4..3c93eb25 100644 --- a/Project_Timer/Core/Localize/TLRkey.swift +++ b/Project_Timer/Core/Localize/TLRkey.swift @@ -46,6 +46,11 @@ enum TLRkey: String { /// 안내 case Common_Popup_Inform + /// 최신버전 정보를 불러오지 못했어요 + case App_Popup_FetchVersionErrorTitle + /// 문제가 계속될 경우 문의 부탁드려요. + case App_Popup_FetchVersionErrorDesc + /// {}시간 경과되었습니다. case System_Noti_StopwatchHourPassed /// 타이머가 종료되었습니다! diff --git a/Project_Timer/Core/Localize/TLRko.swift b/Project_Timer/Core/Localize/TLRko.swift index b7d0353c..e99b42ff 100644 --- a/Project_Timer/Core/Localize/TLRko.swift +++ b/Project_Timer/Core/Localize/TLRko.swift @@ -31,6 +31,9 @@ struct TLRko { case .Common_Popup_Warning: value = "경고" case .Common_Popup_Inform: value = "안내" + case .App_Popup_FetchVersionErrorTitle: value = "최신버전 정보를 불러오지 못했어요" + case .App_Popup_FetchVersionErrorDesc: value = "문제가 계속될 경우 문의 부탁드려요." + case .System_Noti_StopwatchHourPassed: value = "{}시간 경과되었습니다." case .System_Noti_TimerFinished: value = "타이머가 종료되었습니다!" case .System_Noti_Timer5Left: value = "5분 남았습니다" diff --git a/Project_Timer/Core/Localize/TLRzh.swift b/Project_Timer/Core/Localize/TLRzh.swift index 11fd0c8a..d45540ea 100644 --- a/Project_Timer/Core/Localize/TLRzh.swift +++ b/Project_Timer/Core/Localize/TLRzh.swift @@ -31,6 +31,9 @@ struct TLRzh { case .Common_Popup_Warning: value = "警告" case .Common_Popup_Inform: value = "向导" + case .App_Popup_FetchVersionErrorTitle: value = "无法获取最新版本信息。" + case .App_Popup_FetchVersionErrorDesc: value = "如果问题仍然存在,请联系客服。" + case .System_Noti_StopwatchHourPassed: value = "{}时间已过。" case .System_Noti_TimerFinished: value = "计时器已结束 !" case .System_Noti_Timer5Left: value = "还剩5分钟" diff --git a/Project_Timer/Data/API/API.swift b/Project_Timer/Data/API/API.swift new file mode 100644 index 00000000..0a2358f0 --- /dev/null +++ b/Project_Timer/Data/API/API.swift @@ -0,0 +1,30 @@ +// +// API.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/04/17. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Moya + +extension TargetType { + func parameters(from encodable: Encodable) -> [String: Any] { + let encoder = JSONEncoder() + guard let data = try? encoder.encode(encodable), + let dictionary = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else { + return [:] + } + + return dictionary + } +} + +extension JSONEncoder { + static var dateFormatted: JSONEncoder { + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .iso8601 + return encoder + } +} diff --git a/Project_Timer/Data/API/AppVersionAPI.swift b/Project_Timer/Data/API/AppVersionAPI.swift deleted file mode 100644 index 669fabe3..00000000 --- a/Project_Timer/Data/API/AppVersionAPI.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AppVersionAPI.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class AppVersionAPI { - private let network = Network() - private var latestVersionURL: String { - let base = Infos.FirestoreURL.value - #if targetEnvironment(macCatalyst) - return base + "/version/macos" - #else - return base + "/version/ios" - #endif - } - - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: latestVersionURL, method: .get) { result in - completion(result) - } - } -} diff --git a/Project_Timer/Data/API/AuthAPI.swift b/Project_Timer/Data/API/AuthAPI.swift index 79bf7ced..b5092e2d 100644 --- a/Project_Timer/Data/API/AuthAPI.swift +++ b/Project_Timer/Data/API/AuthAPI.swift @@ -2,63 +2,65 @@ // AuthAPI.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/04/17. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya -final class AuthAPI { - private let network = Network() - private var signupURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/auth/signup" - } - private var signinURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/auth/login" - } - private var checkUsersURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/auth/users" - } - private var resetPasswordURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/auth/users/password" - } - - func signup(signupInfo: TestUserSignupInfo, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: self.signupURL, method: .post, param: nil, body: signupInfo) { result in - completion(result) - } +enum AuthAPI { + case postSignup(TestUserSignupRequest) + case postSignin(TestUserSigninRequest) + case getCheckUsername(CheckUsernameRequest) + case getCheckEmail(CheckEmailExitRequest) + case postUpdatePassword(UpdatePasswordRequest) +} + +extension AuthAPI: TargetType { + var baseURL: URL { + return URL(string: NetworkURL.shared.serverURL ?? "nil")! } - func signin(signinInfo: TestUserSigninInfo, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: self.signinURL, method: .post, param: nil, body: signinInfo) { result in - completion(result) + var path: String { + switch self { + case .postSignup: + return "/auth/signup" + case .postSignin: + return "/auth/login" + case .getCheckUsername, .getCheckEmail: + return "/auth/users" + case .postUpdatePassword: + return "/auth/users/password" } } - func checkUsername(username: String, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: self.checkUsersURL, method: .get, param: [ - "username": username - ]) { result in - completion(result) + var method: Moya.Method { + switch self { + case .postSignup, .postSignin, .postUpdatePassword: + return .post + case .getCheckUsername, .getCheckEmail: + return .get } } - func checkEmail(username: String, email: String, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: self.checkUsersURL, method: .get, param: [ - "username": username, - "email": email - ]) { result in - completion(result) + var task: Moya.Task { + switch self { + case .postSignup(let request): + return .requestJSONEncodable(request) + case .postSignin(let request): + return .requestJSONEncodable(request) + case .getCheckUsername(let request): + return .requestParameters(parameters: self.parameters(from: request), encoding: URLEncoding.queryString) + case .getCheckEmail(let request): + return .requestParameters(parameters: self.parameters(from: request), encoding: URLEncoding.queryString) + case .postUpdatePassword(let request): + return .requestJSONEncodable(request) } } - func updatePassword(request: ResetPasswordRequest, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: self.resetPasswordURL, method: .post, body: request) { result in - completion(result) - } + var headers: [String: String]? { + return nil } } + diff --git a/Project_Timer/Data/API/DailysAPI.swift b/Project_Timer/Data/API/DailysAPI.swift index 71e09f9d..8dc39566 100644 --- a/Project_Timer/Data/API/DailysAPI.swift +++ b/Project_Timer/Data/API/DailysAPI.swift @@ -2,33 +2,65 @@ // DailysAPI.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/04/17. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya -final class DailysAPI { - private let network = Network() - private var uploadDailysURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/dailys/upload" +enum DailysAPI { + case postDailys(body: [Daily], headers: [String: String]) + case getDailys + case postRecordTime(RecordTimes) + case getRecordTime + case getSyncLog +} + +extension DailysAPI: TargetType { + var baseURL: URL { + return URL(string: NetworkURL.shared.serverURL ?? "nil")! } - private var getDailysURL: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/dailys" + + var path: String { + switch self { + case .postDailys: + return "/dailys/upload" + case .getDailys: + return "/dailys" + case .postRecordTime, .getRecordTime: + return "/recordTime" + case .getSyncLog: + return "/syncLog" + } + } + + var method: Moya.Method { + switch self { + case .postDailys, .postRecordTime: + return .post + case .getDailys, .getRecordTime, .getSyncLog: + return .get + } } - func upload(dailys: [Daily], completion: @escaping (NetworkResult) -> Void) { - let param = ["gmt": TimeZone.current.secondsFromGMT()] - self.network.request(url: uploadDailysURL, method: .post, param: param, body: dailys) { result in - completion(result) + var task: Moya.Task { + switch self { + case .postDailys(let body, _): + return .requestCustomJSONEncodable(body, encoder: .dateFormatted) + case .postRecordTime(let recordTimes): + return .requestCustomJSONEncodable(recordTimes, encoder: .dateFormatted) + default: + return .requestPlain } } - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: getDailysURL, method: .get) { result in - completion(result) + var headers: [String : String]? { + switch self { + case .postDailys(_, let headers): + return headers + default: + return nil } } } diff --git a/Project_Timer/Data/API/FirebaseAPI.swift b/Project_Timer/Data/API/FirebaseAPI.swift new file mode 100644 index 00000000..7bc058f1 --- /dev/null +++ b/Project_Timer/Data/API/FirebaseAPI.swift @@ -0,0 +1,77 @@ +// +// FirebaseAPI.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/04/17. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Moya + +enum FirebaseAPI { + case getAppVersion + case getServerURL + case getNotification + case getTiTiFunctions + case getUpdateHistorys + case getYoutubeLink + case getSurveys +} + +extension FirebaseAPI: TargetType { + var baseURL: URL { + return URL(string: Infos.FirestoreURL.value)! + } + + var path: String { + switch self { + case .getAppVersion: + #if targetEnvironment(macCatalyst) + return "/version/macos" + #else + return "/version/ios" + #endif + case .getServerURL: + return "/server/url" + case .getNotification: + switch Language.current { + case .ko: return "/notification/ko" + case .en: return "/notification/en" + case .zh: return "/notification/zh" + } + case .getTiTiFunctions: + switch Language.current { + case .ko: return "/titifuncs" + case .en, .zh: return "/titifuncs_eng" + } + case .getUpdateHistorys: + switch Language.current { + case .ko: return "/updates" + case .en, .zh: return "/updates_eng" + } + case .getYoutubeLink: + return "/youtube" + case .getSurveys: + switch Language.current { + case .ko: return "/surveys" + case .en, .zh: return "/surveys_eng" + } + } + } + + var method: Moya.Method { + switch self { + case .getAppVersion, .getServerURL, .getNotification, .getTiTiFunctions, .getUpdateHistorys, .getYoutubeLink, .getSurveys: + return .get + } + } + + var task: Moya.Task { + return .requestPlain + } + + var headers: [String : String]? { + return nil + } +} diff --git a/Project_Timer/Data/API/NotificationAPI.swift b/Project_Timer/Data/API/NotificationAPI.swift deleted file mode 100644 index 96c24aa1..00000000 --- a/Project_Timer/Data/API/NotificationAPI.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// NotificationAPI.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/17. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class NotificationAPI { - private let network = Network() - private var url: String { - let base = Infos.FirestoreURL.value - let path = "/notification" - switch Language.current { - case .ko: return base + path + "/ko" - case .en: return base + path + "/en" - case .zh: return base + path + "/zh" - } - } - - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: url, method: .get) { result in - completion(result) - } - } -} diff --git a/Project_Timer/Data/API/RecordTimesAPI.swift b/Project_Timer/Data/API/RecordTimesAPI.swift deleted file mode 100644 index f970ea0d..00000000 --- a/Project_Timer/Data/API/RecordTimesAPI.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// RecordTimesAPI.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class RecordTimesAPI { - private let network = Network() - private var url: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/recordTime" - } - - func upload(recordTimes: RecordTimes, completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: url, method: .post, param: nil, body: recordTimes) { result in - completion(result) - } - } - - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: url, method: .get) { result in - completion(result) - } - } -} diff --git a/Project_Timer/Data/API/ServerURLAPI.swift b/Project_Timer/Data/API/ServerURLAPI.swift deleted file mode 100644 index 1b0811d8..00000000 --- a/Project_Timer/Data/API/ServerURLAPI.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ServerURLAPI.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class ServerURLAPI { - private let network = Network() - private var url: String { - let base = Infos.FirestoreURL.value - return base + "/server/url" - } - - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: url, method: .get) { result in - completion(result) - } - } -} diff --git a/Project_Timer/Data/API/SyncLogAPI.swift b/Project_Timer/Data/API/SyncLogAPI.swift deleted file mode 100644 index 40876ad5..00000000 --- a/Project_Timer/Data/API/SyncLogAPI.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// SyncLogAPI.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class SyncLogAPI { - private let network = Network() - private var url: String { - let base = NetworkURL.shared.serverURL ?? "nil" - return base + "/syncLog" - } - - func get(completion: @escaping (NetworkResult) -> Void) { - self.network.request(url: url, method: .get) { result in - completion(result) - } - } -} diff --git a/Project_Timer/Data/DTO/FunctionInfo.swift b/Project_Timer/Data/DTO/FunctionInfo.swift deleted file mode 100644 index fb25ded3..00000000 --- a/Project_Timer/Data/DTO/FunctionInfo.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// FunctionInfo.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/06/05. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation - -/// Network 수신 DTO -struct FunctionInfos: Decodable { - let functionInfos: [FunctionInfo] - - enum CodingKeys: String, CodingKey { - case functionInfos = "documents" - } -} - -/// survayInfos 내 DTO -struct FunctionInfo: Decodable { - let title: StringValue - let url: StringValue - - private enum RootKey: String, CodingKey { - case fields - } - private enum FieldKeys: String, CodingKey { - case title, url - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: RootKey.self) - let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - - self.title = try fieldContainer.decode(StringValue.self, forKey: .title) - self.url = try fieldContainer.decode(StringValue.self, forKey: .url) - } -} diff --git a/Project_Timer/Data/DTO/SurveyInfo.swift b/Project_Timer/Data/DTO/SurveyInfo.swift deleted file mode 100644 index 8d45a6f0..00000000 --- a/Project_Timer/Data/DTO/SurveyInfo.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// SurveyInfo.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/07/03. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation - -/// Network 수신 DTO -struct SurveyInfos: Decodable { - let surveyInfos: [SurveyInfo]? - - enum CodingKeys: String, CodingKey { - case surveyInfos = "documents" - } -} - -/// survayInfos 내 DTO -struct SurveyInfo: Decodable { - let title: StringValue - let url: StringValue - - private enum RootKey: String, CodingKey { - case fields - } - private enum FieldKeys: String, CodingKey { - case title, url - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: RootKey.self) - let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - - self.title = try fieldContainer.decode(StringValue.self, forKey: .title) - self.url = try fieldContainer.decode(StringValue.self, forKey: .url) - } -} diff --git a/Project_Timer/Data/DTO/UpdateInfo.swift b/Project_Timer/Data/DTO/UpdateInfo.swift deleted file mode 100644 index 56c35718..00000000 --- a/Project_Timer/Data/DTO/UpdateInfo.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// UpdateInfo.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/06/04. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation - -/// Network 수신 DTO -struct UpdateInfos: Decodable { - var updateInfos: [UpdateInfo] - - enum CodingKeys: String, CodingKey { - case updateInfos = "documents" - } -} - -/// updateInfos 내 DTO -struct UpdateInfo: Decodable, FirestoreValue { - var version: StringValue - var date: StringValue - var text: StringValue - - private enum RootKey: String, CodingKey { - case fields - } - private enum FieldKeys: String, CodingKey { - case version, date, text - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: RootKey.self) - let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - - self.version = try fieldContainer.decode(StringValue.self, forKey: .version) - self.date = try fieldContainer.decode(StringValue.self, forKey: .date) - self.text = try fieldContainer.decode(StringValue.self, forKey: .text) - - self.text = transString(self.text) - } -} diff --git a/Project_Timer/Data/Network/Extension/JSONParameterEncoder+Extension.swift b/Project_Timer/Data/Network/Extension/JSONParameterEncoder+Extension.swift deleted file mode 100644 index 46ed7e74..00000000 --- a/Project_Timer/Data/Network/Extension/JSONParameterEncoder+Extension.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// JSONParameterEncoder+Extension.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/12/21. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation -import Alamofire - -extension JSONParameterEncoder { - static var dateFormatted: JSONParameterEncoder = { - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = .iso8601 - return JSONParameterEncoder(encoder: encoder) - }() -} diff --git a/Project_Timer/Data/Network/Network.swift b/Project_Timer/Data/Network/Network.swift deleted file mode 100644 index e3d731d6..00000000 --- a/Project_Timer/Data/Network/Network.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// Network.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/05/21. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation -import Alamofire - -struct Network { - func request(url: String, method: HTTPMethod, param: [String: Any]? = nil, completion: @escaping (NetworkResult) -> Void) { - var url = url - if let param = param { - var components = URLComponents(string: url) - components?.queryItems = param.map({ key, value in URLQueryItem(name: key, value: "\(value)")}) - if let urlWithQuery = components?.url?.absoluteString { - url = urlWithQuery - } - } - - Session.default.request(url, method: method, interceptor: NetworkInterceptor()) { $0.timeoutInterval = 10 } - .validate() - .response { response in - completion(self.configureNetworkResult(response: response)) - } - .resume() - } - - func request(url: String, method: HTTPMethod, param: [String: Any]? = nil, body: T, completion: @escaping (NetworkResult) -> Void) { - var url = url - if let param = param { - var components = URLComponents(string: url) - components?.queryItems = param.map({ key, value in URLQueryItem(name: key, value: "\(value)")}) - if let urlWithQuery = components?.url?.absoluteString { - url = urlWithQuery - } - } - - Session.default.request(url, method: method, parameters: body, encoder: JSONParameterEncoder.dateFormatted, interceptor: NetworkInterceptor()) { $0.timeoutInterval = 10 } - .validate() - .response { response in - completion(self.configureNetworkResult(response: response)) - } - .resume() - } -} - -extension Network { - private func configureNetworkResult(response: AFDataResponse) -> NetworkResult { - guard let statusCode = response.response?.statusCode else { - print("[Network] Fail: No Status Code, \(String(describing: response.error))") - return NetworkResult(status: response.error?.isRequestRetryError == true ? .FAIL : .TIMEOUT, data: nil) - } - - let status = NetworkStatus.status(statusCode) - - guard let data = response.data else { - print("[Network] Warning(\(statusCode)): No Data") - return NetworkResult(status: status, data: nil) - } - - // server로부터 받은 data가 'null' 값인 경우 추가처리 - if String(data: data, encoding: .utf8) == "null" { - print("[Network] Warning(\(statusCode)): null") - return NetworkResult(status: status, data: nil) - } - - if Infos.isDevMode { - print("[Network] url: \(String(describing: response.request?.url))") - print("[Network] statusCode: \(statusCode)") - print("[Network] data: \(String(data: data, encoding: .utf8)!)") - } - - return NetworkResult(status: status, data: data) - } -} diff --git a/Project_Timer/Data/Network/NetworkController.swift b/Project_Timer/Data/Network/NetworkController.swift deleted file mode 100644 index 7c5593a0..00000000 --- a/Project_Timer/Data/Network/NetworkController.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// NetworkController.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/05/21. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation - -final class NetworkController { - let network: Network - init(network: Network) { - self.network = network - } -} - -extension NetworkController: TiTiFunctionsFetchable { - func getTiTiFunctions(completion: @escaping (Result<[FunctionInfo], NetworkError>) -> Void) { - self.network.request(url: NetworkURL.Firestore.titifuncs, method: .get) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let functionInfos: FunctionInfos = try? JSONDecoder().decode(FunctionInfos.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - completion(.success(functionInfos.functionInfos)) - default: - completion(.failure(NetworkError.error(result))) - } - } - } -} - -extension NetworkController: UpdateHistoryFetchable { - func getUpdateHistorys(completion: @escaping (Result<[UpdateInfo], NetworkError>) -> Void) { - self.network.request(url: NetworkURL.Firestore.updates, method: .get) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let updateInfos: UpdateInfos = try? JSONDecoder().decode(UpdateInfos.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - completion(.success(updateInfos.updateInfos)) - default: - completion(.failure(NetworkError.error(result))) - } - } - } -} - -extension NetworkController: YoutubeLinkFetchable { - func getYoutubeLink(completion: @escaping (Result) -> Void) { - self.network.request(url: NetworkURL.Firestore.youtubeLink, method: .get) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let youtubeLinkInfo: YoutubeLinkInfo = try? JSONDecoder().decode(YoutubeLinkInfo.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - completion(.success(youtubeLinkInfo)) - default: - completion(.failure(NetworkError.error(result))) - } - } - } -} - -extension NetworkController: SurveysFetchable { - func getSurveys(completion: @escaping (Result<[SurveyInfo], NetworkError>) -> Void) { - self.network.request(url: NetworkURL.Firestore.surveys, method: .get) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let surveys: SurveyInfos = try? JSONDecoder().decode(SurveyInfos.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - completion(.success(surveys.surveyInfos ?? [])) - default: - completion(.failure(NetworkError.error(result))) - } - } - } -} diff --git a/Project_Timer/Data/Network/NetworkProtocols.swift b/Project_Timer/Data/Network/NetworkProtocols.swift deleted file mode 100644 index 9810120b..00000000 --- a/Project_Timer/Data/Network/NetworkProtocols.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// NetworkProtocols.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/05/21. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation -import Alamofire - -protocol TiTiFunctionsFetchable { - func getTiTiFunctions(completion: @escaping (Result<[FunctionInfo], NetworkError>) -> Void) -} - -protocol UpdateHistoryFetchable { - func getUpdateHistorys(completion: @escaping (Result<[UpdateInfo], NetworkError>) -> Void) -} - -protocol YoutubeLinkFetchable { - func getYoutubeLink(completion: @escaping (Result) -> Void) -} - -protocol SurveysFetchable { - func getSurveys(completion: @escaping (Result<[SurveyInfo], NetworkError>) -> Void) -} diff --git a/Project_Timer/Data/Network/NetworkResult.swift b/Project_Timer/Data/Network/NetworkResult.swift deleted file mode 100644 index 65ba57d2..00000000 --- a/Project_Timer/Data/Network/NetworkResult.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// NetworkResult.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/10/02. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -struct NetworkResult { - let status: NetworkStatus - let data: Data? -} - -enum NetworkStatus { - case SUCCESS // 200~204, 304 - case FAIL // -1 - case TIMEOUT // -2 - case SERVER(Int) - - static func status(_ statusCode: Int) -> NetworkStatus { - switch statusCode { - case (200...209): return .SUCCESS - case 304: return .SUCCESS - default: return .SERVER(statusCode) - } - } -} diff --git a/Project_Timer/Data/Network/NetworkURL.swift b/Project_Timer/Data/Network/NetworkURL.swift deleted file mode 100644 index 90ab13c0..00000000 --- a/Project_Timer/Data/Network/NetworkURL.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// NetworkURL.swift -// Project_Timer -// -// Created by Kang Minsang on 2022/05/21. -// Copyright © 2022 FDEE. All rights reserved. -// - -import Foundation -import SwiftUI - -class NetworkURL { - static let shared = NetworkURL() - private(set) var serverURL: String? - - private init() { - self.updateServerURL() {} - } - - func updateServerURL(completion: @escaping () -> Void) { - let getServerURLUseCase = GetServerURLUseCase(repository: ServerURLRepository()) - getServerURLUseCase.getServerURL { [weak self] result in - switch result { - case .success(let url): - guard url != "nil" else { - self?.serverURL = nil - completion() - return - } - - self?.serverURL = url - completion() - case .failure(_): - self?.serverURL = nil - completion() - } - } - } - - static let appstoreVersion: String = "https://itunes.apple.com/lookup?id=1519159240&country=kr" - static let appstore: String = "itms-apps://itunes.apple.com/app/id1519159240" - static let developmentList: String = "https://deeply-eggplant-5ec.notion.site/TiTi-Development-List-b089afc1a4eb4cdb8c06840ca9cb1273" - static let instagramToTiTi: String = "https://www.instagram.com/study_withtiti/" - static let instagramToDeveloper: String = "https://www.instagram.com/dev_mindsang/" - static let github: String = "https://github.com/TimerTiTi" - - enum Firestore { - static let domain: String = Infos.FirestoreURL.value - static let links: String = domain + "/links" - static let youtubeLink: String = links + "/youtube" - static var latestVersion: String { - #if targetEnvironment(macCatalyst) - return domain + "/version/macos" - #else - return domain + "version/ios" - #endif - } - - static var surveys: String { - switch Language.current { - case .ko: return domain + "/surveys" - default: return domain + "/surveys_eng" - } - } - - static var titifuncs: String { - switch Language.current { - case .ko: return domain + "/titifuncs" - default: return domain + "/titifuncs_eng" - } - } - - static var updates: String { - switch Language.current { - case .ko: return domain + "/updates?pageSize=100" - default: return domain + "/updates_eng?pageSize=100" - } - } - } - - enum WidgetInfo { - static var calendarWidget: String { - switch Language.current { - case .ko: return "https://titicalendarwidgetkor.simple.ink/" - default: return "https://titicalendarwidgeteng.simple.ink/" - } - } - } -} diff --git a/Project_Timer/Domain/Entity/NetworkError.swift b/Project_Timer/Data/NetworkError.swift similarity index 61% rename from Project_Timer/Domain/Entity/NetworkError.swift rename to Project_Timer/Data/NetworkError.swift index 4050e0cb..8291d9cc 100644 --- a/Project_Timer/Domain/Entity/NetworkError.swift +++ b/Project_Timer/Data/NetworkError.swift @@ -7,63 +7,63 @@ // import Foundation +import Moya +/// 네트워크 에러 enum NetworkError: Error { - case FAIL - case TIMEOUT - case DECODEERROR - case CLIENTERROR(String?) // 400 - case AUTHENTICATION(String?) // 401 - case NOTFOUND(String?) // 404 - case CONFLICT(String?) // 409 - case SERVERERROR(String?) // 500 + case fail + case timeout + case decode + case client(String?) // 400 + case authentication(String?) // 401 + case notFound(String?) // 404 + case conflict(String?) // 409 + case server(String?) // 500 + case errorResponse(TTErrorResponse) // TiTi ErrorResponse - static func error(_ result: NetworkResult) -> NetworkError { - switch result.status { - case .TIMEOUT: - return .TIMEOUT - case .SERVER(let statusCode): - return serverError(statusCode: statusCode, data: result.data) - default: - return .FAIL - } - } - - private static func serverError(statusCode: Int, data: Data?) -> NetworkError { + static func serverError(statusCode: Int, data: Data? = nil) -> NetworkError { // MARK: Decoding 로직 필요 let errorMessage: String? = "" switch statusCode { case 400: - return .CLIENTERROR(errorMessage) + return .client(errorMessage) case 401: - return .AUTHENTICATION(errorMessage) + return .authentication(errorMessage) case 404: - return .NOTFOUND(errorMessage) + return .notFound(errorMessage) case 409: - return .CONFLICT(errorMessage) + return .conflict(errorMessage) case 500: - return .SERVERERROR(errorMessage) + return .server(errorMessage) default: - return .FAIL + return .fail + } + } + + /// ErrorResponse 반환 + static func errorResponse(_ response: Response) -> NetworkError { + guard let errorResponse = try? JSONDecoder().decode(TTErrorResponse.self, from: response.data) else { + return .serverError(statusCode: response.statusCode) } + return .errorResponse(errorResponse) } /// 범용적으로 표시될 수 있는 alert title 값, CLIENTERROR의 경우 VM에서 처리 var title: String { switch self { - case .FAIL: + case .fail: return Localized.string(.Server_Error_NetworkError) - case .TIMEOUT: + case .timeout: return Localized.string(.Server_Error_NetworkTimeout) - case .DECODEERROR: + case .decode: return Localized.string(.Server_Error_NetworkFetchError) - case .AUTHENTICATION(_): + case .authentication(_): return Localized.string(.SignIn_Error_AuthenticationError) - case .NOTFOUND(_): + case .notFound(_): return Localized.string(.Server_Error_NetworkFetchError) - case .CONFLICT(_): + case .conflict(_): return Localized.string(.SignUp_Error_SignupError) - case .SERVERERROR(_): + case .server(_): return Localized.string(.Server_Error_ServerError) default: return Localized.string(.Server_Error_NetworkError) @@ -73,19 +73,19 @@ enum NetworkError: Error { /// 범용적으로 표시될 수 있는 alert message 값, CLIENTERROR의 경우 VM에서 처리 var message: String { switch self { - case .FAIL: + case .fail: return Localized.string(.Server_Error_CheckNetwork) - case .TIMEOUT: + case .timeout: return Localized.string(.Server_Error_CheckNetwork) - case .DECODEERROR: + case .decode: return Localized.string(.Server_Error_DecodeError) - case .AUTHENTICATION(_): + case .authentication(_): return Localized.string(.SignIn_Error_SigninAgain) - case .NOTFOUND(_): + case .notFound(_): return Localized.string(.Server_Error_DecodeError) - case .CONFLICT(_): + case .conflict(_): return Localized.string(.SignUp_Error_EnterDifferentValue) - case .SERVERERROR(_): + case .server(_): return Localized.string(.Server_Error_ServerErrorTryAgain) default: return Localized.string(.Server_Error_CheckNetwork) diff --git a/Project_Timer/Data/Network/NetworkInterceptor.swift b/Project_Timer/Data/NetworkInterceptor.swift similarity index 70% rename from Project_Timer/Data/Network/NetworkInterceptor.swift rename to Project_Timer/Data/NetworkInterceptor.swift index e367ea73..59db227b 100644 --- a/Project_Timer/Data/Network/NetworkInterceptor.swift +++ b/Project_Timer/Data/NetworkInterceptor.swift @@ -8,9 +8,17 @@ import Foundation import Alamofire +import Combine +/// accessToken, refreshToken 주입 final class NetworkInterceptor: RequestInterceptor { static let retryLimit = 3 + static let shared = NetworkInterceptor() + private init() {} + + // Combine binding + private var cancellables = Set() + /// network request 전에 token 설정 func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { guard urlRequest.url?.absoluteString.hasPrefix(NetworkURL.shared.serverURL ?? "nil") == true else { @@ -59,20 +67,27 @@ final class NetworkInterceptor: RequestInterceptor { } extension NetworkInterceptor { + /// signin 과정을 통해 token 재발급 private func signinForToken(completion: @escaping (String?) -> Void) { guard let username = KeyChain.shared.get(key: .username), let password = KeyChain.shared.get(key: .password) else { return } - let signinInfo = TestUserSigninInfo(username: username, password: password) - let authUseCase = AuthUseCase(repository: AuthRepository()) - authUseCase.signin(signinInfo: signinInfo) { result in - switch result { - case .success(let token): - completion(token) - case .failure(let error): - let message = error.alertMessage - print("title: \(error.title)/nmessage: \(error.message)") - completion(nil) + + // TODO: DI 수정 + let api = TTProvider() + let repository = AuthRepository(api: api) + let signinUseCase = SigninUseCase(repository: repository) + + let signinInfo = TestUserSigninRequest(username: username, password: password) + signinUseCase.execute(request: signinInfo) + .sink { comp in + if case .failure(let networkError) = comp { + print("ERROR", #function, networkError) + print(networkError.alertMessage) + completion(nil) + } + } receiveValue: { authInfo in + completion(authInfo.token) } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Data/NetworkURL.swift b/Project_Timer/Data/NetworkURL.swift new file mode 100644 index 00000000..955070b3 --- /dev/null +++ b/Project_Timer/Data/NetworkURL.swift @@ -0,0 +1,69 @@ +// +// NetworkURL.swift +// Project_Timer +// +// Created by Kang Minsang on 2022/05/21. +// Copyright © 2022 FDEE. All rights reserved. +// + +import Foundation +import SwiftUI +import Moya +import Combine + +final class NetworkURL { + static let shared = NetworkURL() + private(set) var serverURL: String? + // Combine binding + private var cancellables = Set() + + private init() { + self.getServerURL() + .sink { _ in } + .store(in: &self.cancellables) + } + + func getServerURL() -> AnyPublisher { + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getServerURLUseCase = GetServerURLUseCase(repository: repository) + + return Future { [weak self] promise in + guard let self else { promise(.success(nil)); return } + + getServerURLUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.serverURL = nil + promise(.success(nil)) + } + } receiveValue: { [weak self] url in + guard url != "nil" else { + self?.serverURL = nil + promise(.success(nil)) + return + } + + self?.serverURL = url + promise(.success(url)) + } + .store(in: &self.cancellables) + } + .eraseToAnyPublisher() + } + + static let appstore: String = "itms-apps://itunes.apple.com/app/id1519159240" + static let instagramToTiTi: String = "https://www.instagram.com/study_withtiti/" + static let github: String = "https://github.com/TimerTiTi" + + enum WidgetInfo { + static var calendarWidget: String { + switch Language.current { + case .ko: return "https://titicalendarwidgetkor.simple.ink/" + default: return "https://titicalendarwidgeteng.simple.ink/" + } + } + } +} diff --git a/Project_Timer/Data/Repository/AppLatestVersionRepository.swift b/Project_Timer/Data/Repository/AppLatestVersionRepository.swift deleted file mode 100644 index a5489f89..00000000 --- a/Project_Timer/Data/Repository/AppLatestVersionRepository.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// AppLatestVersionRepository.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class AppLatestVersionRepository: AppLatestVersionRepositoryInterface { - private let api = AppVersionAPI() - - func get(completion: @escaping (Result) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(AppLatestVersionDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - - default: - completion(.failure(.error(result))) - } - } - } -} diff --git a/Project_Timer/Data/Repository/AuthRepository.swift b/Project_Timer/Data/Repository/AuthRepository.swift index f7076d03..d770b469 100644 --- a/Project_Timer/Data/Repository/AuthRepository.swift +++ b/Project_Timer/Data/Repository/AuthRepository.swift @@ -2,104 +2,54 @@ // AuthRepository.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/05/22. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya +import Combine +import CombineMoya -final class AuthRepository: AuthRepositoryInterface { - private let api = AuthAPI() +final class AuthRepository { + private let api: TTProvider - func signup(signupInfo: TestUserSignupInfo, completion: @escaping (Result) -> Void) { - api.signup(signupInfo: signupInfo) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(AuthDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - - default: - completion(.failure(.error(result))) - } - } + init(api: TTProvider) { + self.api = api } - func signin(signinInfo: TestUserSigninInfo, completion: @escaping (Result) -> Void) { - api.signin(signinInfo: signinInfo) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(AuthDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - - default: - completion(.failure(.error(result))) - } - } + func signup(request: TestUserSignupRequest) -> AnyPublisher { + return self.api.request(.postSignup(request)) + .map(AuthResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } - func checkUsername(username: String, completion: @escaping (Result) -> Void) { - api.checkUsername(username: username) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(SimpleResponse.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - completion(.success(dto)) - - default: - completion(.failure(.error(result))) - } - } + func signin(request: TestUserSigninRequest) -> AnyPublisher { + return self.api.request(.postSignin(request)) + .map(AuthResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } - func checkEmail(username: String, email: String, completion: @escaping (Result) -> Void) { - api.checkEmail(username: username, email: email) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(SimpleResponse.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - completion(.success(dto)) - - default: - completion(.failure(.error(result))) - } - } + func checkUsernameExit(request: CheckUsernameRequest) -> AnyPublisher { + return self.api.request(.getCheckUsername(request)) + .map(SimpleResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } - func updatePassword(request: ResetPasswordRequest, completion: @escaping (Result) -> Void) { - api.updatePassword(request: request) { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(SimpleResponse.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - completion(.success(dto)) - - default: - completion(.failure(.error(result))) - } - } + func checkEmailExit(request: CheckEmailExitRequest) -> AnyPublisher { + return self.api.request(.getCheckEmail(request)) + .map(SimpleResponse.self) + .map { $0.toDomain() } + .catchDecodeError() + } + + func updatePassword(request: UpdatePasswordRequest) -> AnyPublisher { + return self.api.request(.postUpdatePassword(request)) + .map(SimpleResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } } diff --git a/Project_Timer/Data/Repository/DailysRepository.swift b/Project_Timer/Data/Repository/DailysRepository.swift index 2c881834..897d3d2f 100644 --- a/Project_Timer/Data/Repository/DailysRepository.swift +++ b/Project_Timer/Data/Repository/DailysRepository.swift @@ -2,49 +2,35 @@ // DailysRepository.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/06/09. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya +import Combine +import CombineMoya -final class DailysRepository: DailysRepositoryInterface { - private let api = DailysAPI() +final class DailysRepository { + private let api: TTProvider - func upload(dailys: [Daily], completion: @escaping (Result) -> Void) { - api.upload(dailys: dailys) { result in - switch result.status { - case .SUCCESS: - completion(.success(true)) - default: - completion(.failure(.error(result))) - } - } + init(api: TTProvider) { + self.api = api } - func get(completion: @escaping (Result<[Daily], NetworkError>) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dtos = try? JSONDecoder.dateFormatted.decode([DailyDTO].self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let dailys = dtos.map { $0.toDomain() } - completion(.success(dailys)) - default: - completion(.failure(.error(result))) - } - } + func uploadDailys(request: [Daily]) -> AnyPublisher { + let headers: [String: String] = [ + "gmt": "\(TimeZone.current.secondsFromGMT())" + ] + return self.api.request(.postDailys(body: request, headers: headers)) + .map { _ in true } + .catchDecodeError() } - func store(dailys: [Daily], completion: @escaping (Result) -> Void) { - - } - - func fetch(completion: @escaping (Result<[Daily], Error>) -> Void) { - + func getDailys() -> AnyPublisher<[Daily], NetworkError> { + return self.api.request(.getDailys) + .map([DailyResponse].self) + .map { $0.map { $0.toDomain() } } + .catchDecodeError() } } diff --git a/Project_Timer/Data/Repository/FirebaseRepository.swift b/Project_Timer/Data/Repository/FirebaseRepository.swift new file mode 100644 index 00000000..f5acbafa --- /dev/null +++ b/Project_Timer/Data/Repository/FirebaseRepository.swift @@ -0,0 +1,69 @@ +// +// FirebaseRepository.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/05/15. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Moya +import Combine +import CombineMoya + +final class FirebaseRepository { + private let api: TTProvider + + init(api: TTProvider) { + self.api = api + } + + func getAppVersion() -> AnyPublisher { + return self.api.request(.getAppVersion) + .map(AppVersionResponse.self) + .map { $0.toDomain() } + .catchDecodeError() + } + + func getServerURL() -> AnyPublisher { + return self.api.request(.getServerURL) + .map(ServerURLResponse.self) + .map { $0.base.value } + .catchDecodeError() + } + + func getTiTiFunctions() -> AnyPublisher<[FunctionInfo], NetworkError> { + return self.api.request(.getTiTiFunctions) + .map(FunctionResponse.self) + .map { $0.functionInfos } + .catchDecodeError() + } + + func getUpdateHistorys() -> AnyPublisher<[UpdateHistoryInfo], NetworkError> { + return self.api.request(.getUpdateHistorys) + .map(UpdateHistoryResponse.self) + .map { $0.updateInfos } + .catchDecodeError() + } + + func getYoutubeLink() -> AnyPublisher { + return self.api.request(.getYoutubeLink) + .map(YoutubeLinkResponse.self) + .map { $0.url.value } + .catchDecodeError() + } + + func getSurveys() -> AnyPublisher<[SurveyInfo], NetworkError> { + return self.api.request(.getSurveys) + .map(SurveyResponse.self) + .map { $0.surveyInfos ?? [] } + .catchDecodeError() + } + + func getNotification() -> AnyPublisher { + return self.api.request(.getNotification) + .map(NotificationResponse.self) + .map { $0.visible.value == true ? $0.toDomain() : nil } + .catchDecodeError() + } +} diff --git a/Project_Timer/Data/Repository/NotificationRepository.swift b/Project_Timer/Data/Repository/NotificationRepository.swift deleted file mode 100644 index a6585e97..00000000 --- a/Project_Timer/Data/Repository/NotificationRepository.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// NotificationRepository.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/17. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class NotificationRepository: NotificationRepositoryInterface { - private let api = NotificationAPI() - - func get(completion: @escaping (Result) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - if let data = result.data { - guard let dto = try? JSONDecoder.dateFormatted.decode(NotificationDTO.self, from: data) else { - print(String(data: data, encoding: .utf8)!) - completion(.failure(.DECODEERROR)) - return - } - - guard dto.visible.value else { - completion(.success(nil)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - } else { - completion(.success(nil)) - } - default: - completion(.failure(.error(result))) - } - } - } -} diff --git a/Project_Timer/Data/Repository/RecordTimesRepository.swift b/Project_Timer/Data/Repository/RecordTimesRepository.swift index ca64ddf5..a694a57d 100644 --- a/Project_Timer/Data/Repository/RecordTimesRepository.swift +++ b/Project_Timer/Data/Repository/RecordTimesRepository.swift @@ -2,41 +2,32 @@ // RecordTimesRepository.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/06/09. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya +import Combine +import CombineMoya -final class RecordTimesRepository: RecordTimesRepositoryInterface { - private let api = RecordTimesAPI() +final class RecordTimesRepository { + private let api: TTProvider - func upload(recordTimes: RecordTimes, completion: @escaping (Result) -> Void) { - api.upload(recordTimes: recordTimes) { result in - switch result.status { - case .SUCCESS: - completion(.success(true)) - default: - completion(.failure(.error(result))) - } - } + init(api: TTProvider) { + self.api = api } - func get(completion: @escaping (Result) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder.dateFormatted.decode(RecordTimesDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - default: - completion(.failure(.error(result))) - } - } + func upload(request: RecordTimes) -> AnyPublisher { + return self.api.request(.postRecordTime(request)) + .map { _ in true } + .catchDecodeError() + } + + func get() -> AnyPublisher { + return self.api.request(.getRecordTime) + .map(RecordTimesResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } } diff --git a/Project_Timer/Data/Repository/ServerURLRepository.swift b/Project_Timer/Data/Repository/ServerURLRepository.swift deleted file mode 100644 index 2c4d8c2d..00000000 --- a/Project_Timer/Data/Repository/ServerURLRepository.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// ServerURLRepository.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class ServerURLRepository: ServerURLRepositoryInterface { - private let api = ServerURLAPI() - - func get(completion: @escaping (Result) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - guard let data = result.data, - let dto = try? JSONDecoder().decode(ServerURLDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let url = dto.base.value - completion(.success(url)) - - default: - completion(.failure(.error(result))) - } - } - } -} diff --git a/Project_Timer/Data/Repository/SyncLogRepository.swift b/Project_Timer/Data/Repository/SyncLogRepository.swift index 91f45771..dbdf77d8 100644 --- a/Project_Timer/Data/Repository/SyncLogRepository.swift +++ b/Project_Timer/Data/Repository/SyncLogRepository.swift @@ -2,33 +2,26 @@ // SyncLogRepository.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation +import Moya +import Combine +import CombineMoya -final class SyncLogRepository: SyncLogRepositoryInterface { - private let api = SyncLogAPI() +final class SyncLogRepository { + private let api: TTProvider - func get(completion: @escaping (Result) -> Void) { - api.get { result in - switch result.status { - case .SUCCESS: - if let data = result.data { - guard let dto = try? JSONDecoder.dateFormatted.decode(SyncLogDTO.self, from: data) else { - completion(.failure(.DECODEERROR)) - return - } - - let info = dto.toDomain() - completion(.success(info)) - } else { - completion(.success(nil)) - } - default: - completion(.failure(.error(result))) - } - } + init(api: TTProvider) { + self.api = api + } + + func get() -> AnyPublisher { + return self.api.request(.getSyncLog) + .map(SyncLogResponse.self) + .map { $0.toDomain() } + .catchDecodeError() } } diff --git a/Project_Timer/Data/Request/CheckEmailExitRequest.swift b/Project_Timer/Data/Request/CheckEmailExitRequest.swift new file mode 100644 index 00000000..76d22d31 --- /dev/null +++ b/Project_Timer/Data/Request/CheckEmailExitRequest.swift @@ -0,0 +1,14 @@ +// +// CheckEmailExitRequest.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/09. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct CheckEmailExitRequest: Encodable { + let username: String + let email: String +} diff --git a/Project_Timer/Data/Request/CheckUsernameRequest.swift b/Project_Timer/Data/Request/CheckUsernameRequest.swift new file mode 100644 index 00000000..654caac5 --- /dev/null +++ b/Project_Timer/Data/Request/CheckUsernameRequest.swift @@ -0,0 +1,13 @@ +// +// CheckUsernameRequest.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct CheckUsernameRequest: Encodable { + let username: String +} diff --git a/Project_Timer/Domain/Entity/TestUserSigninInfo.swift b/Project_Timer/Data/Request/TestUserSigninRequest.swift similarity index 72% rename from Project_Timer/Domain/Entity/TestUserSigninInfo.swift rename to Project_Timer/Data/Request/TestUserSigninRequest.swift index 74e40008..aaa5e6d6 100644 --- a/Project_Timer/Domain/Entity/TestUserSigninInfo.swift +++ b/Project_Timer/Data/Request/TestUserSigninRequest.swift @@ -1,5 +1,5 @@ // -// TestUserSigninInfo.swift +// TestUserSigninRequest.swift // Project_Timer // // Created by Kang Minsang on 2022/12/21. @@ -8,7 +8,7 @@ import Foundation -struct TestUserSigninInfo: Encodable { +struct TestUserSigninRequest: Encodable { let username: String let password: String } diff --git a/Project_Timer/Domain/Entity/TestUserSignupInfo.swift b/Project_Timer/Data/Request/TestUserSignupRequest.swift similarity index 74% rename from Project_Timer/Domain/Entity/TestUserSignupInfo.swift rename to Project_Timer/Data/Request/TestUserSignupRequest.swift index 5d079ed5..0a54add3 100644 --- a/Project_Timer/Domain/Entity/TestUserSignupInfo.swift +++ b/Project_Timer/Data/Request/TestUserSignupRequest.swift @@ -1,5 +1,5 @@ // -// TestUserSignupInfo.swift +// TestUserSignupRequest.swift // Project_Timer // // Created by Kang Minsang on 2022/12/21. @@ -8,7 +8,7 @@ import Foundation -struct TestUserSignupInfo: Encodable { +struct TestUserSignupRequest: Encodable { let username: String let email: String let password: String diff --git a/Project_Timer/Data/Request/ResetPasswordRequest.swift b/Project_Timer/Data/Request/UpdatePasswordRequest.swift similarity index 74% rename from Project_Timer/Data/Request/ResetPasswordRequest.swift rename to Project_Timer/Data/Request/UpdatePasswordRequest.swift index 8379acbd..759191fe 100644 --- a/Project_Timer/Data/Request/ResetPasswordRequest.swift +++ b/Project_Timer/Data/Request/UpdatePasswordRequest.swift @@ -1,5 +1,5 @@ // -// ResetPasswordRequest.swift +// UpdatePasswordRequest.swift // Project_Timer // // Created by Kang Minsang on 2024/03/16. @@ -8,7 +8,7 @@ import Foundation -struct ResetPasswordRequest: Encodable { +struct UpdatePasswordRequest: Encodable { let username: String let email: String let newPassword: String diff --git a/Project_Timer/Data/DTO/AppLatestVersionDTO.swift b/Project_Timer/Data/Response/AppVersionResponse.swift similarity index 56% rename from Project_Timer/Data/DTO/AppLatestVersionDTO.swift rename to Project_Timer/Data/Response/AppVersionResponse.swift index 4747242e..eb818971 100644 --- a/Project_Timer/Data/DTO/AppLatestVersionDTO.swift +++ b/Project_Timer/Data/Response/AppVersionResponse.swift @@ -1,16 +1,17 @@ // -// AppLatestVersionDTO.swift +// AppVersionResponse.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/05/15. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation -struct AppLatestVersionDTO: Decodable { - let latestVersion: StringValue - let forced: BooleanValue +/// TiTi 최신버전 정보 +struct AppVersionResponse: Decodable { + let latestVersion: FirebaseStringValue + let forced: FirebaseBooleanValue private enum RootKey: String, CodingKey { case fields @@ -25,12 +26,12 @@ struct AppLatestVersionDTO: Decodable { let container = try decoder.container(keyedBy: RootKey.self) let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - self.latestVersion = try fieldContainer.decode(StringValue.self, forKey: .latestVersion) - self.forced = try fieldContainer.decode(BooleanValue.self, forKey: .forced) + self.latestVersion = try fieldContainer.decode(FirebaseStringValue.self, forKey: .latestVersion) + self.forced = try fieldContainer.decode(FirebaseBooleanValue.self, forKey: .forced) } } -extension AppLatestVersionDTO { +extension AppVersionResponse { func toDomain() -> AppLatestVersionInfo { return .init( latestVersion: self.latestVersion.value, diff --git a/Project_Timer/Data/DTO/AuthDTO.swift b/Project_Timer/Data/Response/AuthResponse.swift similarity index 83% rename from Project_Timer/Data/DTO/AuthDTO.swift rename to Project_Timer/Data/Response/AuthResponse.swift index 45389128..9494ee0c 100644 --- a/Project_Timer/Data/DTO/AuthDTO.swift +++ b/Project_Timer/Data/Response/AuthResponse.swift @@ -1,5 +1,5 @@ // -// AuthDTO.swift +// AuthResponse.swift // Project_Timer // // Created by Kang Minsang on 2023/12/15. @@ -8,14 +8,14 @@ import Foundation -struct AuthDTO: Decodable { +struct AuthResponse: Decodable { var id: Int var username: String var email: String var token: String } -extension AuthDTO { +extension AuthResponse { func toDomain() -> AuthInfo { return .init( id: self.id, diff --git a/Project_Timer/Data/DTO/DailyDTO.swift b/Project_Timer/Data/Response/DailyResponse.swift similarity index 95% rename from Project_Timer/Data/DTO/DailyDTO.swift rename to Project_Timer/Data/Response/DailyResponse.swift index ab6d825e..d15c1c61 100644 --- a/Project_Timer/Data/DTO/DailyDTO.swift +++ b/Project_Timer/Data/Response/DailyResponse.swift @@ -8,7 +8,7 @@ import Foundation -struct DailyDTO: Decodable { +struct DailyResponse: Decodable { var id: Int? var status: String? var day: Date @@ -23,7 +23,7 @@ struct TaskHistoryDTO: Decodable { var endDate: Date } -extension DailyDTO { +extension DailyResponse { func toDomain() -> Daily { return .init( id: self.id, diff --git a/Project_Timer/Data/DTO/firebaseValue/BooleanValue.swift b/Project_Timer/Data/Response/FirebaseValue/FirebaseBooleanValue.swift similarity index 80% rename from Project_Timer/Data/DTO/firebaseValue/BooleanValue.swift rename to Project_Timer/Data/Response/FirebaseValue/FirebaseBooleanValue.swift index fdfd8bb9..f9b69dd0 100644 --- a/Project_Timer/Data/DTO/firebaseValue/BooleanValue.swift +++ b/Project_Timer/Data/Response/FirebaseValue/FirebaseBooleanValue.swift @@ -1,12 +1,12 @@ // -// BooleanValue.swift +// FirebaseBooleanValue.swift // Project_Timer // // Created by Kang Minsang on 2023/12/03. // Copyright © 2023 FDEE. All rights reserved. // -struct BooleanValue: Decodable { +struct FirebaseBooleanValue: Decodable { let value: Bool init(value: Bool) { diff --git a/Project_Timer/Data/DTO/firebaseValue/StringArrayValue.swift b/Project_Timer/Data/Response/FirebaseValue/FirebaseStringArrayValue.swift similarity index 64% rename from Project_Timer/Data/DTO/firebaseValue/StringArrayValue.swift rename to Project_Timer/Data/Response/FirebaseValue/FirebaseStringArrayValue.swift index efd9e14c..4d71814b 100644 --- a/Project_Timer/Data/DTO/firebaseValue/StringArrayValue.swift +++ b/Project_Timer/Data/Response/FirebaseValue/FirebaseStringArrayValue.swift @@ -1,5 +1,5 @@ // -// StringArrayValue.swift +// FirebaseStringArrayValue.swift // Project_Timer // // Created by Kang Minsang on 2023/12/17. @@ -8,10 +8,10 @@ import Foundation -struct StringArrayValue: Decodable { +struct FirebaseStringArrayValue: Decodable { let arrayValue: StringValues } struct StringValues: Decodable { - let values: [StringValue] + let values: [FirebaseStringValue] } diff --git a/Project_Timer/Data/DTO/firebaseValue/StringValue.swift b/Project_Timer/Data/Response/FirebaseValue/FirebaseStringValue.swift similarity index 82% rename from Project_Timer/Data/DTO/firebaseValue/StringValue.swift rename to Project_Timer/Data/Response/FirebaseValue/FirebaseStringValue.swift index 1e7f8bee..b69fd906 100644 --- a/Project_Timer/Data/DTO/firebaseValue/StringValue.swift +++ b/Project_Timer/Data/Response/FirebaseValue/FirebaseStringValue.swift @@ -1,5 +1,5 @@ // -// StringValue.swift +// FirebaseStringValue.swift // Project_Timer // // Created by Kang Minsang on 2022/07/03. @@ -8,7 +8,7 @@ import Foundation -struct StringValue: Decodable { +struct FirebaseStringValue: Decodable { let value: String init(value: String) { diff --git a/Project_Timer/Data/DTO/firebaseValue/FirestoreValue.swift b/Project_Timer/Data/Response/FirebaseValue/FirestoreValue.swift similarity index 69% rename from Project_Timer/Data/DTO/firebaseValue/FirestoreValue.swift rename to Project_Timer/Data/Response/FirebaseValue/FirestoreValue.swift index 3e309e35..6080f43a 100644 --- a/Project_Timer/Data/DTO/firebaseValue/FirestoreValue.swift +++ b/Project_Timer/Data/Response/FirebaseValue/FirestoreValue.swift @@ -10,8 +10,8 @@ import Foundation protocol FirestoreValue {} extension FirestoreValue { - func transString(_ stringValue: StringValue) -> StringValue { + func transString(_ stringValue: FirebaseStringValue) -> FirebaseStringValue { let transString = stringValue.value.replacingOccurrences(of: "\\n", with: "\n") - return StringValue(value: transString) + return FirebaseStringValue(value: transString) } } diff --git a/Project_Timer/Data/Response/FunctionResponse.swift b/Project_Timer/Data/Response/FunctionResponse.swift new file mode 100644 index 00000000..3172c444 --- /dev/null +++ b/Project_Timer/Data/Response/FunctionResponse.swift @@ -0,0 +1,18 @@ +// +// FunctionResponse.swift +// Project_Timer +// +// Created by Kang Minsang on 2022/06/05. +// Copyright © 2022 FDEE. All rights reserved. +// + +import Foundation + +/// Network 수신 DTO +struct FunctionResponse: Decodable { + let functionInfos: [FunctionInfo] + + enum CodingKeys: String, CodingKey { + case functionInfos = "documents" + } +} diff --git a/Project_Timer/Data/DTO/NotificationDTO.swift b/Project_Timer/Data/Response/NotificationResponse.swift similarity index 62% rename from Project_Timer/Data/DTO/NotificationDTO.swift rename to Project_Timer/Data/Response/NotificationResponse.swift index 49a90cc9..75807eca 100644 --- a/Project_Timer/Data/DTO/NotificationDTO.swift +++ b/Project_Timer/Data/Response/NotificationResponse.swift @@ -8,12 +8,12 @@ import Foundation -struct NotificationDTO: Decodable, FirestoreValue { - var title: StringValue - var text: StringValue - var notiTitles: StringArrayValue - var notiTexts: StringArrayValue - var visible: BooleanValue +struct NotificationResponse: Decodable, FirestoreValue { + var title: FirebaseStringValue + var text: FirebaseStringValue + var notiTitles: FirebaseStringArrayValue + var notiTexts: FirebaseStringArrayValue + var visible: FirebaseBooleanValue private enum RootKey: String, CodingKey { case fields @@ -31,18 +31,18 @@ struct NotificationDTO: Decodable, FirestoreValue { let container = try decoder.container(keyedBy: RootKey.self) let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - self.title = try fieldContainer.decode(StringValue.self, forKey: .title) - self.text = try fieldContainer.decode(StringValue.self, forKey: .text) - self.notiTitles = try fieldContainer.decode(StringArrayValue.self, forKey: .notiTitles) - self.notiTexts = try fieldContainer.decode(StringArrayValue.self, forKey: .notiTexts) - self.visible = try fieldContainer.decode(BooleanValue.self, forKey: .visible) + self.title = try fieldContainer.decode(FirebaseStringValue.self, forKey: .title) + self.text = try fieldContainer.decode(FirebaseStringValue.self, forKey: .text) + self.notiTitles = try fieldContainer.decode(FirebaseStringArrayValue.self, forKey: .notiTitles) + self.notiTexts = try fieldContainer.decode(FirebaseStringArrayValue.self, forKey: .notiTexts) + self.visible = try fieldContainer.decode(FirebaseBooleanValue.self, forKey: .visible) self.title = transString(self.title) self.text = transString(self.text) } } -extension NotificationDTO { +extension NotificationResponse { func toDomain() -> NotificationInfo { return .init( title: self.title.value, diff --git a/Project_Timer/Data/DTO/RecordTimesDTO.swift b/Project_Timer/Data/Response/RecordTimesResponse.swift similarity index 94% rename from Project_Timer/Data/DTO/RecordTimesDTO.swift rename to Project_Timer/Data/Response/RecordTimesResponse.swift index b4046d14..63bcaf80 100644 --- a/Project_Timer/Data/DTO/RecordTimesDTO.swift +++ b/Project_Timer/Data/Response/RecordTimesResponse.swift @@ -8,7 +8,7 @@ import Foundation -struct RecordTimesDTO: Decodable { +struct RecordTimesResponse: Decodable { var recordingMode: Int var recording: Bool var recordStartAt: Date @@ -24,7 +24,7 @@ struct RecordTimesDTO: Decodable { var recordStartTimeline: [Int] } -extension RecordTimesDTO { +extension RecordTimesResponse { func toDomain() -> RecordTimes { return .init( recordTask: self.recordTask, diff --git a/Project_Timer/Data/DTO/ServerURLDTO.swift b/Project_Timer/Data/Response/ServerURLResponse.swift similarity index 58% rename from Project_Timer/Data/DTO/ServerURLDTO.swift rename to Project_Timer/Data/Response/ServerURLResponse.swift index 3acd0e16..1fc92d5f 100644 --- a/Project_Timer/Data/DTO/ServerURLDTO.swift +++ b/Project_Timer/Data/Response/ServerURLResponse.swift @@ -1,15 +1,16 @@ // -// ServerURLDTO.swift +// ServerURLResponse.swift // Project_Timer // -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. +// Created by Kang Minsang on 2024/05/15. +// Copyright © 2024 FDEE. All rights reserved. // import Foundation -struct ServerURLDTO: Decodable { - let base: StringValue +/// TiTi 서버 URL 정보 +struct ServerURLResponse: Decodable { + let base: FirebaseStringValue private enum RootKey: String, CodingKey { case fields @@ -23,6 +24,6 @@ struct ServerURLDTO: Decodable { let container = try decoder.container(keyedBy: RootKey.self) let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - self.base = try fieldContainer.decode(StringValue.self, forKey: .base) + self.base = try fieldContainer.decode(FirebaseStringValue.self, forKey: .base) } } diff --git a/Project_Timer/Data/Response/SimpleResponse.swift b/Project_Timer/Data/Response/SimpleResponse.swift index 0edc3ebd..ecc0200c 100644 --- a/Project_Timer/Data/Response/SimpleResponse.swift +++ b/Project_Timer/Data/Response/SimpleResponse.swift @@ -8,7 +8,14 @@ import Foundation +/// Node.js 에서 받는 간단한 형태 struct SimpleResponse: Decodable { let data: Bool let message: String } + +extension SimpleResponse { + func toDomain() -> Bool { + return self.data + } +} diff --git a/Project_Timer/Data/Response/SurveyResponse.swift b/Project_Timer/Data/Response/SurveyResponse.swift new file mode 100644 index 00000000..5a3c6e5a --- /dev/null +++ b/Project_Timer/Data/Response/SurveyResponse.swift @@ -0,0 +1,18 @@ +// +// SurveyResponse.swift +// Project_Timer +// +// Created by Kang Minsang on 2022/07/03. +// Copyright © 2022 FDEE. All rights reserved. +// + +import Foundation + +/// Network 수신 DTO +struct SurveyResponse: Decodable { + let surveyInfos: [SurveyInfo]? + + enum CodingKeys: String, CodingKey { + case surveyInfos = "documents" + } +} diff --git a/Project_Timer/Data/DTO/SyncLogDTO.swift b/Project_Timer/Data/Response/SyncLogResponse.swift similarity index 84% rename from Project_Timer/Data/DTO/SyncLogDTO.swift rename to Project_Timer/Data/Response/SyncLogResponse.swift index e01f2c0d..7545006c 100644 --- a/Project_Timer/Data/DTO/SyncLogDTO.swift +++ b/Project_Timer/Data/Response/SyncLogResponse.swift @@ -8,12 +8,12 @@ import Foundation -struct SyncLogDTO: Decodable { +struct SyncLogResponse: Decodable { let updatedAt: Date let dailysCount: Int } -extension SyncLogDTO { +extension SyncLogResponse { func toDomain() -> SyncLog { return .init( updatedAt: self.updatedAt, diff --git a/Project_Timer/Data/Response/TTErrorResponse.swift b/Project_Timer/Data/Response/TTErrorResponse.swift new file mode 100644 index 00000000..f2d3905c --- /dev/null +++ b/Project_Timer/Data/Response/TTErrorResponse.swift @@ -0,0 +1,16 @@ +// +// TTErrorResponse.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/05/15. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +/// TiTi 에러 +struct TTErrorResponse: Decodable { + let code: String + let message: String + let errors: [String: String] +} diff --git a/Project_Timer/Data/Response/TTResponse.swift b/Project_Timer/Data/Response/TTResponse.swift new file mode 100644 index 00000000..24167fa7 --- /dev/null +++ b/Project_Timer/Data/Response/TTResponse.swift @@ -0,0 +1,14 @@ +// +// TTResponse.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct TTResponse: Decodable { + let code: String + let message: String +} diff --git a/Project_Timer/Data/Response/UpdateHistoryResponse.swift b/Project_Timer/Data/Response/UpdateHistoryResponse.swift new file mode 100644 index 00000000..ea5d6523 --- /dev/null +++ b/Project_Timer/Data/Response/UpdateHistoryResponse.swift @@ -0,0 +1,18 @@ +// +// UpdateHistoryResponse.swift +// Project_Timer +// +// Created by Kang Minsang on 2022/06/04. +// Copyright © 2022 FDEE. All rights reserved. +// + +import Foundation + +/// Network 수신 DTO +struct UpdateHistoryResponse: Decodable { + var updateInfos: [UpdateHistoryInfo] + + enum CodingKeys: String, CodingKey { + case updateInfos = "documents" + } +} diff --git a/Project_Timer/Data/DTO/YoutubeLinkInfo.swift b/Project_Timer/Data/Response/YoutubeLinkResponse.swift similarity index 78% rename from Project_Timer/Data/DTO/YoutubeLinkInfo.swift rename to Project_Timer/Data/Response/YoutubeLinkResponse.swift index 79a89ea0..c3b4ed38 100644 --- a/Project_Timer/Data/DTO/YoutubeLinkInfo.swift +++ b/Project_Timer/Data/Response/YoutubeLinkResponse.swift @@ -9,8 +9,8 @@ import Foundation /// youtubeInfo DTO -struct YoutubeLinkInfo: Decodable { - let url: StringValue +struct YoutubeLinkResponse: Decodable { + let url: FirebaseStringValue private enum RootKey: String, CodingKey { case fields @@ -23,6 +23,6 @@ struct YoutubeLinkInfo: Decodable { let container = try decoder.container(keyedBy: RootKey.self) let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - self.url = try fieldContainer.decode(StringValue.self, forKey: .url) + self.url = try fieldContainer.decode(FirebaseStringValue.self, forKey: .url) } } diff --git a/Project_Timer/Data/TTProvider.swift b/Project_Timer/Data/TTProvider.swift new file mode 100644 index 00000000..2f33b12b --- /dev/null +++ b/Project_Timer/Data/TTProvider.swift @@ -0,0 +1,80 @@ +// +// TTProvider.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/05/15. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import RxSwift +import Combine +import Moya + +/// 공통적인 에러를 반환하는 Provider +final class TTProvider: MoyaProvider { + func request(_ token: T) -> AnyPublisher { + return Future { promise in + super.request(token) { result in + switch result { + case .success(let response): + print("\nTTProvider success", token, "\(token.baseURL)\(token.path)") +// print("-->", String(data: response.data, encoding: .utf8), "\n") + if (200...299).contains(response.statusCode) { + promise(.success(response)) + } else { + // ErrorResponse 디코딩 + promise(.failure(NetworkError.errorResponse(response))) + } + promise(.success(response)) + case .failure(let error): + print("\nTTProvider failure", token, "\(token.baseURL)\(token.path)") +// print("-->", error.localizedDescription, "\n") + promise(.failure(self.handleError(error))) + } + } + } + .eraseToAnyPublisher() + } + + private func handleError(_ error: Error) -> NetworkError { + if let moyaError = error as? MoyaError { + switch moyaError { + case .statusCode(let response): + return NetworkError.serverError(statusCode: response.statusCode) + default: + return NetworkError.fail + } + } + return NetworkError.fail + } +} + +extension Publisher { + /// Repository의 공통적인 Decode 에러를 반환하는 Publisher + func catchDecodeError() -> AnyPublisher { + return self + .mapError { error in return error as? NetworkError ?? .decode } + .eraseToAnyPublisher() + } +} + +extension Publisher where Output == Response, Failure == NetworkError { + /// TTProvider를 사용한 경우 map operator 사용 + func map(_ type: D.Type) -> AnyPublisher { + return self.tryMap { response in + do { + let jsonDecoder = JSONDecoder() + jsonDecoder.dateDecodingStrategy = .iso8601 + let decodedData = try jsonDecoder.decode(D.self, from: response.data) + return decodedData + } catch { + throw NetworkError.decode + } + } + .mapError { error in + error as? NetworkError ?? NetworkError.fail + } + .eraseToAnyPublisher() + } +} diff --git a/Project_Timer/Domain/Entity/FunctionInfo.swift b/Project_Timer/Domain/Entity/FunctionInfo.swift new file mode 100644 index 00000000..36343c52 --- /dev/null +++ b/Project_Timer/Domain/Entity/FunctionInfo.swift @@ -0,0 +1,29 @@ +// +// FunctionInfo.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct FunctionInfo: Decodable { + let title: FirebaseStringValue + let url: FirebaseStringValue + + private enum RootKey: String, CodingKey { + case fields + } + private enum FieldKeys: String, CodingKey { + case title, url + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: RootKey.self) + let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) + + self.title = try fieldContainer.decode(FirebaseStringValue.self, forKey: .title) + self.url = try fieldContainer.decode(FirebaseStringValue.self, forKey: .url) + } +} diff --git a/Project_Timer/Data/DTO/LastestVersionInfo.swift b/Project_Timer/Domain/Entity/LastestVersionInfo.swift similarity index 72% rename from Project_Timer/Data/DTO/LastestVersionInfo.swift rename to Project_Timer/Domain/Entity/LastestVersionInfo.swift index cc7851df..3d02ff9f 100644 --- a/Project_Timer/Data/DTO/LastestVersionInfo.swift +++ b/Project_Timer/Domain/Entity/LastestVersionInfo.swift @@ -10,8 +10,8 @@ import Foundation /// latestVersionDTO struct LastestVersionInfo: Decodable { - let iOS: StringValue - let macOS: StringValue + let iOS: FirebaseStringValue + let macOS: FirebaseStringValue private enum RootKey: String, CodingKey { case fields @@ -25,7 +25,7 @@ struct LastestVersionInfo: Decodable { let container = try decoder.container(keyedBy: RootKey.self) let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) - self.iOS = try fieldContainer.decode(StringValue.self, forKey: .iOS) - self.macOS = try fieldContainer.decode(StringValue.self, forKey: .macOS) + self.iOS = try fieldContainer.decode(FirebaseStringValue.self, forKey: .iOS) + self.macOS = try fieldContainer.decode(FirebaseStringValue.self, forKey: .macOS) } } diff --git a/Project_Timer/Domain/Entity/SurveyInfo.swift b/Project_Timer/Domain/Entity/SurveyInfo.swift new file mode 100644 index 00000000..939af8be --- /dev/null +++ b/Project_Timer/Domain/Entity/SurveyInfo.swift @@ -0,0 +1,29 @@ +// +// SurveyInfo.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct SurveyInfo: Decodable { + let title: FirebaseStringValue + let url: FirebaseStringValue + + private enum RootKey: String, CodingKey { + case fields + } + private enum FieldKeys: String, CodingKey { + case title, url + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: RootKey.self) + let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) + + self.title = try fieldContainer.decode(FirebaseStringValue.self, forKey: .title) + self.url = try fieldContainer.decode(FirebaseStringValue.self, forKey: .url) + } +} diff --git a/Project_Timer/Domain/Entity/UpdateHistoryInfo.swift b/Project_Timer/Domain/Entity/UpdateHistoryInfo.swift new file mode 100644 index 00000000..3456ca29 --- /dev/null +++ b/Project_Timer/Domain/Entity/UpdateHistoryInfo.swift @@ -0,0 +1,33 @@ +// +// UpdateHistoryInfo.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation + +struct UpdateHistoryInfo: Decodable, FirestoreValue { + var version: FirebaseStringValue + var date: FirebaseStringValue + var text: FirebaseStringValue + + private enum RootKey: String, CodingKey { + case fields + } + private enum FieldKeys: String, CodingKey { + case version, date, text + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: RootKey.self) + let fieldContainer = try container.nestedContainer(keyedBy: FieldKeys.self, forKey: .fields) + + self.version = try fieldContainer.decode(FirebaseStringValue.self, forKey: .version) + self.date = try fieldContainer.decode(FirebaseStringValue.self, forKey: .date) + self.text = try fieldContainer.decode(FirebaseStringValue.self, forKey: .text) + + self.text = transString(self.text) + } +} diff --git a/Project_Timer/Domain/Interface/AppLatestVersionRepositoryInterface.swift b/Project_Timer/Domain/Interface/AppLatestVersionRepositoryInterface.swift deleted file mode 100644 index 21b67b62..00000000 --- a/Project_Timer/Domain/Interface/AppLatestVersionRepositoryInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// AppLatestVersionRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol AppLatestVersionRepositoryInterface { - func get(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/Interface/AuthRepositoryInterface.swift b/Project_Timer/Domain/Interface/AuthRepositoryInterface.swift deleted file mode 100644 index bc8ef903..00000000 --- a/Project_Timer/Domain/Interface/AuthRepositoryInterface.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// AuthRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol AuthRepositoryInterface { - func signup(signupInfo: TestUserSignupInfo, completion: @escaping (Result) -> Void) - func signin(signinInfo: TestUserSigninInfo, completion: @escaping (Result) -> Void) - func checkUsername(username: String, completion: @escaping (Result) -> Void) - func checkEmail(username: String, email: String, completion: @escaping (Result) -> Void) - func updatePassword(request: ResetPasswordRequest, completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/Interface/DailyRepositoryInterface.swift b/Project_Timer/Domain/Interface/DailyRepositoryInterface.swift deleted file mode 100644 index 84a952a8..00000000 --- a/Project_Timer/Domain/Interface/DailyRepositoryInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// DailysRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol DailysRepositoryInterface { - func upload(dailys: [Daily], completion: @escaping (Result) -> Void) - func get(completion: @escaping (Result<[Daily], NetworkError>) -> Void) -} diff --git a/Project_Timer/Domain/Interface/NotificationRepositoryInterface.swift b/Project_Timer/Domain/Interface/NotificationRepositoryInterface.swift deleted file mode 100644 index b440f9d9..00000000 --- a/Project_Timer/Domain/Interface/NotificationRepositoryInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// NotificationRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/17. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol NotificationRepositoryInterface { - func get(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/Interface/RecordTimesRepositoryInterface.swift b/Project_Timer/Domain/Interface/RecordTimesRepositoryInterface.swift deleted file mode 100644 index c8abcb51..00000000 --- a/Project_Timer/Domain/Interface/RecordTimesRepositoryInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// RecordTimesRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol RecordTimesRepositoryInterface { - func upload(recordTimes: RecordTimes, completion: @escaping (Result) -> Void) - func get(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/Interface/ServerURLRepositoryInterface.swift b/Project_Timer/Domain/Interface/ServerURLRepositoryInterface.swift deleted file mode 100644 index 00fbbf36..00000000 --- a/Project_Timer/Domain/Interface/ServerURLRepositoryInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// ServerURLRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol ServerURLRepositoryInterface { - func get(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/Interface/SyncLogRepositoryInterface.swift b/Project_Timer/Domain/Interface/SyncLogRepositoryInterface.swift deleted file mode 100644 index e5b90c75..00000000 --- a/Project_Timer/Domain/Interface/SyncLogRepositoryInterface.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// SyncLogRepositoryInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol SyncLogRepositoryInterface { - func get(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Domain/UseCase/Auth/CheckEmailExitUseCase.swift b/Project_Timer/Domain/UseCase/Auth/CheckEmailExitUseCase.swift new file mode 100644 index 00000000..02c6e973 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Auth/CheckEmailExitUseCase.swift @@ -0,0 +1,22 @@ +// +// CheckEmailExitUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/06. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class CheckEmailExitUseCase { + private let repository: AuthRepository // TODO: 프로토콜로 수정 + + init(repository: AuthRepository) { + self.repository = repository + } + + func execute(request: CheckEmailExitRequest) -> AnyPublisher { + return self.repository.checkEmailExit(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/Auth/CheckUsernameExitUseCsae.swift b/Project_Timer/Domain/UseCase/Auth/CheckUsernameExitUseCsae.swift new file mode 100644 index 00000000..fe16e0a0 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Auth/CheckUsernameExitUseCsae.swift @@ -0,0 +1,22 @@ +// +// CheckUsernameExitUseCsae.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/06. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class CheckUsernameExitUseCsae { + private let repository: AuthRepository // TODO: 프로토콜로 수정 + + init(repository: AuthRepository) { + self.repository = repository + } + + func execute(request: CheckUsernameRequest) -> AnyPublisher { + return self.repository.checkUsernameExit(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/Auth/SigninUseCase.swift b/Project_Timer/Domain/UseCase/Auth/SigninUseCase.swift new file mode 100644 index 00000000..87e6c513 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Auth/SigninUseCase.swift @@ -0,0 +1,22 @@ +// +// SigninUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/06. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class SigninUseCase { + private let repository: AuthRepository // TODO: 프로토콜로 수정 + + init(repository: AuthRepository) { + self.repository = repository + } + + func execute(request: TestUserSigninRequest) -> AnyPublisher { + return self.repository.signin(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/Auth/SignupUseCase.swift b/Project_Timer/Domain/UseCase/Auth/SignupUseCase.swift new file mode 100644 index 00000000..f4d68ec0 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Auth/SignupUseCase.swift @@ -0,0 +1,22 @@ +// +// PostSignupUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/06. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class SignupUseCase { + private let repository: AuthRepository // TODO: 프로토콜로 수정 + + init(repository: AuthRepository) { + self.repository = repository + } + + func execute(request: TestUserSignupRequest) -> AnyPublisher { + return self.repository.signup(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/Auth/UpdatePasswordUseCase.swift b/Project_Timer/Domain/UseCase/Auth/UpdatePasswordUseCase.swift new file mode 100644 index 00000000..8b0c6f34 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Auth/UpdatePasswordUseCase.swift @@ -0,0 +1,22 @@ +// +// UpdatePasswordUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/06. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class UpdatePasswordUseCase { + private let repository: AuthRepository // TODO: 프로토콜로 수정 + + init(repository: AuthRepository) { + self.repository = repository + } + + func execute(request: UpdatePasswordRequest) -> AnyPublisher { + return self.repository.updatePassword(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/AuthUseCase.swift b/Project_Timer/Domain/UseCase/AuthUseCase.swift deleted file mode 100644 index 3d2fb506..00000000 --- a/Project_Timer/Domain/UseCase/AuthUseCase.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// AuthUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class AuthUseCase: AuthUseCaseInterface { - let repository: AuthRepositoryInterface - - init(repository: AuthRepositoryInterface) { - self.repository = repository - } - - func signup(signupInfo: TestUserSignupInfo, completion: @escaping (Result) -> Void) { - self.repository.signup(signupInfo: signupInfo) { result in - // AuthInfo -> token 값반 반환 - switch result { - case .success(let authInfo): - completion(.success(authInfo.token)) - case .failure(let networkError): - completion(.failure(networkError)) - } - } - } - - func signin(signinInfo: TestUserSigninInfo, completion: @escaping (Result) -> Void) { - self.repository.signin(signinInfo: signinInfo) { result in - // AuthInfo -> token 값반 반환 - switch result { - case .success(let authInfo): - completion(.success(authInfo.token)) - case .failure(let networkError): - completion(.failure(networkError)) - } - } - } - - func checkUsername(username: String, completion: @escaping (Result) -> Void) { - self.repository.checkUsername(username: username) { result in - switch result { - case .success(let simpleResponse): - completion(.success(simpleResponse)) - case .failure(let networkError): - completion(.failure(networkError)) - } - } - } - - func checkEmail(username: String, email: String, completion: @escaping (Result) -> Void) { - self.repository.checkEmail(username: username, email: email) { result in - switch result { - case .success(let simpleResponse): - completion(.success(simpleResponse)) - case .failure(let networkError): - completion(.failure(networkError)) - } - } - } - - func updatePassword(request: ResetPasswordRequest, completion: @escaping (Result) -> Void) { - self.repository.updatePassword(request: request) { result in - switch result { - case .success(let simpleResponse): - completion(.success(simpleResponse)) - case .failure(let networkError): - completion(.failure(networkError)) - } - } - } -} diff --git a/Project_Timer/Domain/UseCase/Dailys/GetDailysUseCase.swift b/Project_Timer/Domain/UseCase/Dailys/GetDailysUseCase.swift new file mode 100644 index 00000000..6a5228a2 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Dailys/GetDailysUseCase.swift @@ -0,0 +1,22 @@ +// +// GetDailysUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetDailysUseCase { + let repository: DailysRepository // TODO: 프로토콜로 수정 + + init(repository: DailysRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher<[Daily], NetworkError> { + return self.repository.getDailys() + } +} diff --git a/Project_Timer/Domain/UseCase/Dailys/PostDailysUseCase.swift b/Project_Timer/Domain/UseCase/Dailys/PostDailysUseCase.swift new file mode 100644 index 00000000..0ebe05d1 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Dailys/PostDailysUseCase.swift @@ -0,0 +1,22 @@ +// +// PostDailysUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class PostDailysUseCase { + private let repository: DailysRepository // TODO: 프로토콜로 수정 + + init(repository: DailysRepository) { + self.repository = repository + } + + func execute(request: [Daily]) -> AnyPublisher { + return self.repository.uploadDailys(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/DailysUseCase.swift b/Project_Timer/Domain/UseCase/DailysUseCase.swift deleted file mode 100644 index 4ef1e7a9..00000000 --- a/Project_Timer/Domain/UseCase/DailysUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// DailysUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class DailysUseCase: DailysUseCaseInterface { - let repository: DailysRepositoryInterface - - init(repository: DailysRepositoryInterface) { - self.repository = repository - } - - func uploadDailys(dailys: [Daily], completion: @escaping (Result) -> Void) { - self.repository.upload(dailys: dailys) { result in - completion(result) - } - } - - func getDailys(completion: @escaping (Result<[Daily], NetworkError>) -> Void) { - self.repository.get() { result in - completion(result) - } - } -} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetAppVersionUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetAppVersionUseCase.swift new file mode 100644 index 00000000..f518c90b --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetAppVersionUseCase.swift @@ -0,0 +1,22 @@ +// +// GetAppVersionUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetAppVersionUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.getAppVersion() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetNotificationUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetNotificationUseCase.swift new file mode 100644 index 00000000..44bd8b63 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetNotificationUseCase.swift @@ -0,0 +1,22 @@ +// +// GetNotificationUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetNotificationUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.getNotification() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetServerURLUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetServerURLUseCase.swift new file mode 100644 index 00000000..eadce9da --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetServerURLUseCase.swift @@ -0,0 +1,22 @@ +// +// GetServerURLUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetServerURLUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.getServerURL() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetSurveysUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetSurveysUseCase.swift new file mode 100644 index 00000000..d80ce932 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetSurveysUseCase.swift @@ -0,0 +1,22 @@ +// +// GetSurveysUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetSurveysUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher<[SurveyInfo], NetworkError> { + return self.repository.getSurveys() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetTiTiFunctionsUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetTiTiFunctionsUseCase.swift new file mode 100644 index 00000000..334dbfb7 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetTiTiFunctionsUseCase.swift @@ -0,0 +1,22 @@ +// +// GetTiTiFunctionsUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetTiTiFunctionsUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher<[FunctionInfo], NetworkError> { + return self.repository.getTiTiFunctions() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetUpdateHistorysUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetUpdateHistorysUseCase.swift new file mode 100644 index 00000000..1a44d996 --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetUpdateHistorysUseCase.swift @@ -0,0 +1,22 @@ +// +// GetUpdateHistorysUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetUpdateHistorysUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher<[UpdateHistoryInfo], NetworkError> { + return self.repository.getUpdateHistorys() + } +} diff --git a/Project_Timer/Domain/UseCase/Firebase/GetYoutubeLinkUseCase.swift b/Project_Timer/Domain/UseCase/Firebase/GetYoutubeLinkUseCase.swift new file mode 100644 index 00000000..0fad765d --- /dev/null +++ b/Project_Timer/Domain/UseCase/Firebase/GetYoutubeLinkUseCase.swift @@ -0,0 +1,22 @@ +// +// GetYoutubeLinkUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/06/29. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetYoutubeLinkUseCase { + private let repository: FirebaseRepository // TODO: 프로토콜로 수정 + + init(repository: FirebaseRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.getYoutubeLink() + } +} diff --git a/Project_Timer/Domain/UseCase/GetLatestVersionUseCase.swift b/Project_Timer/Domain/UseCase/GetLatestVersionUseCase.swift deleted file mode 100644 index f726fa6e..00000000 --- a/Project_Timer/Domain/UseCase/GetLatestVersionUseCase.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// GetLatestVersionUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class GetLatestVersionUseCase: GetLatestVersionUseCaseInterface { - let repository: AppLatestVersionRepositoryInterface - - init(repository: AppLatestVersionRepositoryInterface) { - self.repository = repository - } - - func getLatestVersion(completion: @escaping (Result) -> Void) { - self.repository.get { result in - completion(result) - } - } -} diff --git a/Project_Timer/Domain/UseCase/GetNotificationUseCase.swift b/Project_Timer/Domain/UseCase/GetNotificationUseCase.swift deleted file mode 100644 index c48bb243..00000000 --- a/Project_Timer/Domain/UseCase/GetNotificationUseCase.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// GetNotificationUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/17. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class GetNotificationUseCase: GetNotificationUseCaseInterface { - let repository: NotificationRepositoryInterface - - init(repository: NotificationRepositoryInterface) { - self.repository = repository - } - - func getNoti(completion: @escaping (Result) -> Void) { - self.repository.get() { result in - completion(result) - } - } -} diff --git a/Project_Timer/Domain/UseCase/GetServerURLUseCase.swift b/Project_Timer/Domain/UseCase/GetServerURLUseCase.swift deleted file mode 100644 index 88f402a8..00000000 --- a/Project_Timer/Domain/UseCase/GetServerURLUseCase.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// GetServerURLUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class GetServerURLUseCase: GetServerURLUseCaseInterface { - let repository: ServerURLRepositoryInterface - - init(repository: ServerURLRepositoryInterface) { - self.repository = repository - } - - func getServerURL(completion: @escaping (Result) -> Void) { - self.repository.get { result in - completion(result) - } - } -} diff --git a/Project_Timer/Domain/UseCase/NotificationUseCase.swift b/Project_Timer/Domain/UseCase/Notification/NotificationUseCase.swift similarity index 100% rename from Project_Timer/Domain/UseCase/NotificationUseCase.swift rename to Project_Timer/Domain/UseCase/Notification/NotificationUseCase.swift diff --git a/Project_Timer/Domain/UseCase/RecordTimes/GetRecordTimeUseCase.swift b/Project_Timer/Domain/UseCase/RecordTimes/GetRecordTimeUseCase.swift new file mode 100644 index 00000000..39a6d269 --- /dev/null +++ b/Project_Timer/Domain/UseCase/RecordTimes/GetRecordTimeUseCase.swift @@ -0,0 +1,22 @@ +// +// GetRecordTimeUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetRecordTimeUseCase { + private let repository: RecordTimesRepository // TODO: 프로토콜로 수정 + + init(repository: RecordTimesRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.get() + } +} diff --git a/Project_Timer/Domain/UseCase/RecordTimes/PostRecordTimeUseCase.swift b/Project_Timer/Domain/UseCase/RecordTimes/PostRecordTimeUseCase.swift new file mode 100644 index 00000000..bb0ac2e8 --- /dev/null +++ b/Project_Timer/Domain/UseCase/RecordTimes/PostRecordTimeUseCase.swift @@ -0,0 +1,22 @@ +// +// PostRecordTimeUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class PostRecordTimeUseCase { + private let repository: RecordTimesRepository // TODO: 프로토콜로 수정 + + init(repository: RecordTimesRepository) { + self.repository = repository + } + + func execute(request: RecordTimes) -> AnyPublisher { + self.repository.upload(request: request) + } +} diff --git a/Project_Timer/Domain/UseCase/RecordTimesUseCase.swift b/Project_Timer/Domain/UseCase/RecordTimesUseCase.swift deleted file mode 100644 index a9104688..00000000 --- a/Project_Timer/Domain/UseCase/RecordTimesUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// RecordTimesUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class RecordTimesUseCase: RecordTimesUseCaseInterface { - let repository: RecordTimesRepositoryInterface - - init(repository: RecordTimesRepositoryInterface) { - self.repository = repository - } - - func uploadRecordTimes(recordTimes: RecordTimes, completion: @escaping (Result) -> Void) { - self.repository.upload(recordTimes: recordTimes) { result in - completion(result) - } - } - - func getRecordTimes(completion: @escaping (Result) -> Void) { - self.repository.get() { result in - completion(result) - } - } -} diff --git a/Project_Timer/Domain/UseCase/SyncLog/GetSyncLogUseCase.swift b/Project_Timer/Domain/UseCase/SyncLog/GetSyncLogUseCase.swift new file mode 100644 index 00000000..7702ecf7 --- /dev/null +++ b/Project_Timer/Domain/UseCase/SyncLog/GetSyncLogUseCase.swift @@ -0,0 +1,22 @@ +// +// GetSyncLogUseCase.swift +// Project_Timer +// +// Created by Kang Minsang on 2024/07/07. +// Copyright © 2024 FDEE. All rights reserved. +// + +import Foundation +import Combine + +final class GetSyncLogUseCase { + private let repository: SyncLogRepository // TODO: 프로토콜로 수정 + + init(repository: SyncLogRepository) { + self.repository = repository + } + + func execute() -> AnyPublisher { + return self.repository.get() + } +} diff --git a/Project_Timer/Domain/UseCase/SyncLogUseCase.swift b/Project_Timer/Domain/UseCase/SyncLogUseCase.swift deleted file mode 100644 index 0d16aa1a..00000000 --- a/Project_Timer/Domain/UseCase/SyncLogUseCase.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// SyncLogUseCase.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -final class SyncLogUseCase: SyncLogUseCaseInterface { - let repository: SyncLogRepositoryInterface - - init(repository: SyncLogRepositoryInterface) { - self.repository = repository - } - - func getSyncLog(completion: @escaping (Result) -> Void) { - self.repository.get() { result in - completion(result) - } - } -} diff --git a/Project_Timer/Present/Interface/AuthUseCaseInterface.swift b/Project_Timer/Present/Interface/AuthUseCaseInterface.swift deleted file mode 100644 index 8317a62f..00000000 --- a/Project_Timer/Present/Interface/AuthUseCaseInterface.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// AuthUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol AuthUseCaseInterface { - var repository: AuthRepositoryInterface { get } - func signup(signupInfo: TestUserSignupInfo, completion: @escaping (Result) -> Void) - func signin(signinInfo: TestUserSigninInfo, completion: @escaping (Result) -> Void) - func checkUsername(username: String, completion: @escaping (Result) -> Void) - func checkEmail(username: String, email: String, completion: @escaping (Result) -> Void) - func updatePassword(request: ResetPasswordRequest, completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Interface/DailysUseCaseInterface.swift b/Project_Timer/Present/Interface/DailysUseCaseInterface.swift deleted file mode 100644 index a268ad1b..00000000 --- a/Project_Timer/Present/Interface/DailysUseCaseInterface.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// DailysUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol DailysUseCaseInterface { - var repository: DailysRepositoryInterface { get } - func uploadDailys(dailys: [Daily], completion: @escaping (Result) -> Void) - func getDailys(completion: @escaping (Result<[Daily], NetworkError>) -> Void) -} diff --git a/Project_Timer/Present/Interface/GetLatestVersionUseCaseInterface.swift b/Project_Timer/Present/Interface/GetLatestVersionUseCaseInterface.swift deleted file mode 100644 index 946c3fce..00000000 --- a/Project_Timer/Present/Interface/GetLatestVersionUseCaseInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GetLatestVersionUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/03. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol GetLatestVersionUseCaseInterface { - var repository: AppLatestVersionRepositoryInterface { get } - func getLatestVersion(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Interface/GetNotificationUseCaseInterface.swift b/Project_Timer/Present/Interface/GetNotificationUseCaseInterface.swift deleted file mode 100644 index 3695ac3a..00000000 --- a/Project_Timer/Present/Interface/GetNotificationUseCaseInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GetNotificationUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/17. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol GetNotificationUseCaseInterface { - var repository: NotificationRepositoryInterface { get } - func getNoti(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Interface/GetServerURLUseCaseInterface.swift b/Project_Timer/Present/Interface/GetServerURLUseCaseInterface.swift deleted file mode 100644 index 5a7fc481..00000000 --- a/Project_Timer/Present/Interface/GetServerURLUseCaseInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GetServerURLUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/15. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol GetServerURLUseCaseInterface { - var repository: ServerURLRepositoryInterface { get } - func getServerURL(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Interface/RecordTimesUseCaseInterface.swift b/Project_Timer/Present/Interface/RecordTimesUseCaseInterface.swift deleted file mode 100644 index 290bf1c8..00000000 --- a/Project_Timer/Present/Interface/RecordTimesUseCaseInterface.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// RecordTimesUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol RecordTimesUseCaseInterface { - var repository: RecordTimesRepositoryInterface { get } - func uploadRecordTimes(recordTimes: RecordTimes, completion: @escaping (Result) -> Void) - func getRecordTimes(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Interface/SyncLogUseCaseInterface.swift b/Project_Timer/Present/Interface/SyncLogUseCaseInterface.swift deleted file mode 100644 index 55631a5a..00000000 --- a/Project_Timer/Present/Interface/SyncLogUseCaseInterface.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// SyncLogUseCaseInterface.swift -// Project_Timer -// -// Created by Kang Minsang on 2023/12/16. -// Copyright © 2023 FDEE. All rights reserved. -// - -import Foundation - -protocol SyncLogUseCaseInterface { - var repository: SyncLogRepositoryInterface { get } - func getSyncLog(completion: @escaping (Result) -> Void) -} diff --git a/Project_Timer/Present/Setting/Main/SettingVC.swift b/Project_Timer/Present/Setting/Main/SettingVC.swift index 5c90e2f9..6a6d78b5 100644 --- a/Project_Timer/Present/Setting/Main/SettingVC.swift +++ b/Project_Timer/Present/Setting/Main/SettingVC.swift @@ -9,6 +9,8 @@ import UIKit import Combine import MessageUI +import Moya +import Combine final class SettingVC: UIViewController { static let identifier = "SettingVC" @@ -60,8 +62,11 @@ extension SettingVC { } private func configureViewModel() { - let getLatestVersionUseCase = GetLatestVersionUseCase(repository: AppLatestVersionRepository()) - self.viewModel = SettingVM(getLatestVersionUseCase: getLatestVersionUseCase, isIpad: UIDevice.current.userInterfaceIdiom == .pad) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getAppVersionUseCase = GetAppVersionUseCase(repository: repository) + self.viewModel = SettingVM(getAppVersionUseCase: getAppVersionUseCase, isIpad: UIDevice.current.userInterfaceIdiom == .pad) } private func bindAll() { diff --git a/Project_Timer/Present/Setting/Main/SettingVM.swift b/Project_Timer/Present/Setting/Main/SettingVM.swift index 1fa5e8d4..c36d96ab 100644 --- a/Project_Timer/Present/Setting/Main/SettingVM.swift +++ b/Project_Timer/Present/Setting/Main/SettingVM.swift @@ -10,14 +10,16 @@ import Foundation import Combine final class SettingVM { - private let getLatestVersionUseCase: GetLatestVersionUseCaseInterface + private let getAppVersionUseCase: GetAppVersionUseCase @Published private(set) var cells: [[SettingCellInfo]] = [] @Published private(set) var latestVersionFetched: Bool = false private(set) var sections: [String] = [] private let isIpad: Bool + // Combine binding + private var cancellables = Set() - init(getLatestVersionUseCase: GetLatestVersionUseCaseInterface, isIpad: Bool) { - self.getLatestVersionUseCase = getLatestVersionUseCase + init(getAppVersionUseCase: GetAppVersionUseCase, isIpad: Bool) { + self.getAppVersionUseCase = getAppVersionUseCase self.isIpad = isIpad self.configureSections() self.configureCells() @@ -85,14 +87,15 @@ final class SettingVM { self.cells = cells - self.getLatestVersionUseCase.getLatestVersion { [weak self] result in - switch result { - case .success(let latestVersionInfo): - versionCell.updateSubTitle(to: Localized.string(.Settings_Button_VersionInfoDesc)+": \(latestVersionInfo.latestVersion)") - self?.latestVersionFetched = true - case .failure(let error): - print(error.alertMessage) - } - } + self.getAppVersionUseCase.execute() + .sink { completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + } + } receiveValue: { [weak self] appLatestVersionInfo in + versionCell.updateSubTitle(to: Localized.string(.Settings_Button_VersionInfoDesc)+": \(appLatestVersionInfo.latestVersion)") + self?.latestVersionFetched = true + } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVC.swift b/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVC.swift index bf72249d..161114b5 100644 --- a/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVC.swift +++ b/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya final class SettingFunctionsListVC: UIViewController { static let identifier = "SettingFunctionsListVC" @@ -40,12 +41,6 @@ final class SettingFunctionsListVC: UIViewController { self?.functionList.collectionViewLayout.invalidateLayout() } } - - @IBAction func goToYoutube(_ sender: Any) { - guard let link = self.viewModel?.youtubeLink, - let url = URL(string: link) else { return } - UIApplication.shared.open(url, options: [:]) - } } extension SettingFunctionsListVC { @@ -64,9 +59,12 @@ extension SettingFunctionsListVC { } private func configureViewModel() { - // MARK: NetworkController 를 생성하는 부분에 대한 고민이 필요 - let networkController = NetworkController(network: Network()) - self.viewModel = SettingFunctionsListVM(networkController: networkController) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getTiTiFunctionsUseCase = GetTiTiFunctionsUseCase(repository: repository) + + self.viewModel = SettingFunctionsListVM(getTiTiFunctionsUseCase: getTiTiFunctionsUseCase) } private func stopLoader() { diff --git a/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVM.swift b/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVM.swift index 5eb82994..affaa61e 100644 --- a/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVM.swift +++ b/Project_Timer/Present/Setting/Service/SettingFunctionsList/SettingFunctionsListVM.swift @@ -9,39 +9,29 @@ import Foundation import Combine -typealias FunctionInfoFetchable = (TiTiFunctionsFetchable & YoutubeLinkFetchable) - final class SettingFunctionsListVM { - private let networkController: FunctionInfoFetchable + private let getTiTiFunctionsUseCase: GetTiTiFunctionsUseCase @Published private(set) var infos: [FunctionInfo] = [] @Published private(set) var warning: (title: String, text: String)? private(set) var youtubeLink: String? + // Combine binding + private var cancellables = Set() - init(networkController: FunctionInfoFetchable) { - self.networkController = networkController + init(getTiTiFunctionsUseCase: GetTiTiFunctionsUseCase) { + self.getTiTiFunctionsUseCase = getTiTiFunctionsUseCase self.configureInfos() - self.configureYoutubeLink() } private func configureInfos() { - self.networkController.getTiTiFunctions { [weak self] result in - switch result { - case .success(let functionInfos): + self.getTiTiFunctionsUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.warning = networkError.alertMessage + } + } receiveValue: { [weak self] functionInfos in self?.infos = functionInfos - case .failure(let error): - self?.warning = error.alertMessage - } - } - } - - private func configureYoutubeLink() { - self.networkController.getYoutubeLink { [weak self] result in - switch result { - case .success(let youtubeLinkInfo): - self?.youtubeLink = youtubeLinkInfo.url.value - case .failure(let error): - self?.warning = error.alertMessage } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVC.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVC.swift index 82e72b58..b1ef71d3 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVC.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya final class SettingTiTiLabVC: UIViewController { static let identifier = "SettingTiTiLabVC" @@ -107,8 +108,12 @@ extension SettingTiTiLabVC { } private func showBetaSigninSignupVC(signin: Bool) { - let authUseCase = AuthUseCase(repository: AuthRepository()) - let viewModel = SignupSigninVM(authUseCase: authUseCase, isSignin: signin) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let signupUseCase = SignupUseCase(repository: repository) + let signinUseCase = SigninUseCase(repository: repository) + let viewModel = SignupSigninVM(signupUseCase: signupUseCase, signinUseCase: signinUseCase, isSignin: signin) let vc = SignupSigninVC(viewModel: viewModel) self.navigationController?.pushViewController(vc, animated: true) } @@ -150,9 +155,12 @@ extension SettingTiTiLabVC { } private func configureViewModel() { - // MARK: NetworkController 생성 관련 로직고민이 필요 - let networkController = NetworkController(network: Network()) - self.viewModel = SettingTiTiLabVM(networkController: networkController) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getSurveysUseCase = GetSurveysUseCase(repository: repository) + + self.viewModel = SettingTiTiLabVM(getSurveysUseCase: getSurveysUseCase) } private func stopLoader() { diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVM.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVM.swift index 927bca06..f548c3f2 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVM.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/SettingTiTiLabVM.swift @@ -10,23 +10,27 @@ import Foundation import Combine final class SettingTiTiLabVM { - let networkController: SurveysFetchable + let getSurveysUseCase: GetSurveysUseCase @Published private(set) var infos: [SurveyInfo] = [] @Published private(set) var warning: (title: String, text: String)? + // Combine binding + private var cancellables = Set() - init(networkController: SurveysFetchable) { - self.networkController = networkController + init(getSurveysUseCase: GetSurveysUseCase) { + self.getSurveysUseCase = getSurveysUseCase self.configureInfos() } private func configureInfos() { - self.networkController.getSurveys { [weak self] result in - switch result { - case .success(let surveyInfos): + self.getSurveysUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.warning = networkError.alertMessage + } + } receiveValue: { [weak self] surveyInfos in self?.infos = surveyInfos - case .failure(let error): - self?.warning = error.alertMessage } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailModel.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailModel.swift index 8d5ab4f7..49ecb9d5 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailModel.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailModel.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import Combine // MARK: State final class ResetPasswordEmailModel: ObservableObject { @@ -30,12 +31,14 @@ final class ResetPasswordEmailModel: ObservableObject { @Published var errorMessage: ErrorMessage? @Published var email: String = "" + // Combine binding + private var cancellables = Set() - let authUseCase: AuthUseCaseInterface + private let checkEmailExitUseCase: CheckEmailExitUseCase private let infos: ResetPasswordInfosForEmail - init(authUseCase: AuthUseCaseInterface, infos: ResetPasswordInfosForEmail) { - self.authUseCase = authUseCase + init(checkEmailExitUseCase: CheckEmailExitUseCase, infos: ResetPasswordInfosForEmail) { + self.checkEmailExitUseCase = checkEmailExitUseCase self.infos = infos } @@ -79,20 +82,22 @@ extension ResetPasswordEmailModel { // email done 액션 func checkEmail() { - self.authUseCase.checkEmail(username: self.infos.nickname, email: self.email) { [weak self] result in - switch result { - case .success(let simpleResponse): - self?.validEmail = simpleResponse.data - case .failure(let error): - self?.validEmail = false - switch error { - case .NOTFOUND(_): - self?.errorMessage = .notExist - default: - self?.errorMessage = .serverError - print("Error: \(error.title), \(error.message)") + self.checkEmailExitUseCase.execute(request: .init(username: self.infos.nickname, email: self.email)) + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.validEmail = false + switch networkError { + case .notFound(_): + self?.errorMessage = .notExist + default: + self?.errorMessage = .serverError + print(networkError.alertMessage) + } } + } receiveValue: { [weak self] valid in + self?.validEmail = valid } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailView.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailView.swift index 568fe6bf..be7b59f4 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailView.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Email/ResetPasswordEmailView.swift @@ -7,6 +7,8 @@ // import SwiftUI +import Combine +import Moya struct ResetPasswordEmailView: View { @ObservedObject private var keyboard = KeyboardResponder.shared @@ -32,12 +34,11 @@ struct ResetPasswordEmailView: View { .navigationDestination(for: ResetPasswordEmailRoute.self) { destination in switch destination { case .resetPassword: - let authUseCase = self.model.authUseCase - let infos = self.model.resetPasswordInfosForPassword - let viewModel = ResetPasswordModel( - authUseCase: authUseCase, - infos: infos - ) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let updatePasswordUseCase = UpdatePasswordUseCase(repository: repository) + let viewModel = ResetPasswordModel(updatePasswordUseCase: updatePasswordUseCase, infos: model.resetPasswordInfosForPassword) ResetPasswordView(model: viewModel) } } @@ -99,13 +100,13 @@ struct ResetPasswordEmailView: View { struct ResetPasswordEmailView_Previews: PreviewProvider { static var previews: some View { - ResetPasswordEmailView( - model: ResetPasswordEmailModel(authUseCase: AuthUseCase(repository: AuthRepository()), infos: ResetPasswordInfosForEmail(nickname: "minsang"))) - .environmentObject(ResetPasswordEnvironment()) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let checkEmailExitUseCase = CheckEmailExitUseCase(repository: repository) + let viewModel = ResetPasswordEmailModel(checkEmailExitUseCase: checkEmailExitUseCase, infos: .init(nickname: "minsang")) - ResetPasswordEmailView( - model: ResetPasswordEmailModel(authUseCase: AuthUseCase(repository: AuthRepository()), infos: ResetPasswordInfosForEmail(nickname: "minsang"))) + ResetPasswordEmailView(model: viewModel) .environmentObject(ResetPasswordEnvironment()) - .environment(\.locale, .init(identifier: "en")) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameModel.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameModel.swift index abe7836b..006c2b13 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameModel.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameModel.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import Combine // MARK: State final class ResetPasswordNicknameModel: ObservableObject { @@ -28,13 +29,14 @@ final class ResetPasswordNicknameModel: ObservableObject { @Published var focus: TTSignupTextFieldView.type? @Published var validNickname: Bool? @Published var errorMessage: ErrorMessage? - @Published var nickname: String = "" + // Combine binding + private var cancellables = Set() - let authUseCase: AuthUseCaseInterface + private let checkUsenameExitUseCase: CheckUsernameExitUseCsae - init(authUseCase: AuthUseCaseInterface) { - self.authUseCase = authUseCase + init(checkUsenameExitUseCase: CheckUsernameExitUseCsae) { + self.checkUsenameExitUseCase = checkUsenameExitUseCase } var nicknameWarningVisible: Bool { @@ -76,20 +78,22 @@ extension ResetPasswordNicknameModel { // nickname done 액션 func checkNickname() { - self.authUseCase.checkUsername(username: self.nickname) { [weak self] result in - switch result { - case .success(let simpleResponse): - self?.validNickname = simpleResponse.data - case .failure(let error): - self?.validNickname = false - switch error { - case .NOTFOUND(_): - self?.errorMessage = .notExist - default: - self?.errorMessage = .serverError - print("Error: \(error.title), \(error.message)") + self.checkUsenameExitUseCase.execute(request: .init(username: self.nickname)) + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.validNickname = false + switch networkError { + case .notFound(_): + self?.errorMessage = .notExist + default: + self?.errorMessage = .serverError + print(networkError.alertMessage) + } } + } receiveValue: { [weak self] valid in + self?.validNickname = valid } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameView.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameView.swift index 5a13df3a..7d916547 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameView.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Nickname/ResetPasswordNicknameView.swift @@ -7,6 +7,8 @@ // import SwiftUI +import Combine +import Moya struct ResetPasswordNicknameView: View { @ObservedObject private var keyboard = KeyboardResponder.shared @@ -50,12 +52,11 @@ struct ResetPasswordNicknameView: View { .navigationDestination(for: ResetPasswordNicknameRoute.self) { destination in switch destination { case .resetPasswordEmail: - let authUseCase = self.model.authUseCase - let infos = model.resetPasswordInfosForEmail - let viewModel = ResetPasswordEmailModel( - authUseCase: authUseCase, - infos: infos - ) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let checkEmailExitUseCase = CheckEmailExitUseCase(repository: repository) + let viewModel = ResetPasswordEmailModel(checkEmailExitUseCase: checkEmailExitUseCase, infos: model.resetPasswordInfosForEmail) ResetPasswordEmailView(model: viewModel) } } @@ -120,13 +121,14 @@ struct ResetPasswordNicknameView: View { struct ResetPasswordNicknameView_Previews: PreviewProvider { static var previews: some View { - ResetPasswordNicknameView( - model: ResetPasswordNicknameModel(authUseCase: AuthUseCase(repository: AuthRepository()))) - .environmentObject(ResetPasswordEnvironment()) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let checkUsernameExitUseCase = CheckUsernameExitUseCsae(repository: repository) + let viewModel = ResetPasswordNicknameModel(checkUsenameExitUseCase: checkUsernameExitUseCase) ResetPasswordNicknameView( - model: ResetPasswordNicknameModel(authUseCase: AuthUseCase(repository: AuthRepository()))) + model: viewModel) .environmentObject(ResetPasswordEnvironment()) - .environment(\.locale, .init(identifier: "en")) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordModel.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordModel.swift index 76a057de..f79f3c2f 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordModel.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordModel.swift @@ -42,12 +42,14 @@ final class ResetPasswordModel: ObservableObject { @Published var password: String = "" @Published var password2: String = "" + // Combine binding + private var cancellables = Set() - let authUseCase: AuthUseCaseInterface + private let updatePasswordUseCase: UpdatePasswordUseCase private let infos: ResetPasswordInfosForPassword - init(authUseCase: AuthUseCaseInterface, infos: ResetPasswordInfosForPassword) { - self.authUseCase = authUseCase + init(updatePasswordUseCase: UpdatePasswordUseCase, infos: ResetPasswordInfosForPassword) { + self.updatePasswordUseCase = updatePasswordUseCase self.infos = infos } @@ -130,27 +132,29 @@ extension ResetPasswordModel { } // 비밀번호가 일치하는 경우 서버 통신 else { - let request = ResetPasswordRequest( + let request = UpdatePasswordRequest( username: self.infos.nickname, email: self.infos.email, newPassword: self.password2 ) - self.authUseCase.updatePassword(request: request) { [weak self] result in - switch result { - case .success(let simpleResponse): - self?.validPassword2 = simpleResponse.data - case .failure(let error): - self?.validPassword2 = false - switch error { - case .NOTFOUND(_): - self?.errorMessage = .notExist - default: - self?.errorMessage = .serverError - print("Error: \(error.title), \(error.message)") + self.updatePasswordUseCase.execute(request: request) + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.validPassword2 = false + switch networkError { + case .notFound(_): + self?.errorMessage = .notExist + default: + self?.errorMessage = .serverError + print(networkError.alertMessage) + } } + } receiveValue: { [weak self] success in + self?.validPassword2 = success } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordRoute.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordRoute.swift similarity index 100% rename from Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordRoute.swift rename to Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordRoute.swift diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordView.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordView.swift index 0cee0f3d..9f8dffea 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordView.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/Password/ResetPasswordView.swift @@ -7,6 +7,8 @@ // import SwiftUI +import Combine +import Moya struct ResetPasswordView: View { @ObservedObject private var keyboard = KeyboardResponder.shared @@ -132,11 +134,14 @@ struct ResetPasswordView: View { } struct ResetPasswordView_Previews: PreviewProvider { - static let infos = SignupInfosForPassword(type: .normal, venderInfo: nil, emailInfo: SignupEmailInfo(email: "freedeveloper97@gmail.com", verificationKey: "abcd1234")) - static var previews: some View { - ResetPasswordView( - model: ResetPasswordModel(authUseCase: AuthUseCase(repository: AuthRepository()), infos: ResetPasswordInfosForPassword(nickname: "minsang", email: "freedeveloper97@gmail.com")) - ).environmentObject(ResetPasswordEnvironment()) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let updatePasswordUseCase = UpdatePasswordUseCase(repository: repository) + let viewModel = ResetPasswordModel(updatePasswordUseCase: updatePasswordUseCase, infos: .init(nickname: "minsang", email: "freedeveloper97@gmail.com")) + + ResetPasswordView(model: viewModel) + .environmentObject(ResetPasswordEnvironment()) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordVC.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordVC.swift index e43414c7..a3688c24 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordVC.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/ResetPassword/ResetPasswordVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya import SwiftUI final class ResetPasswordVC: PortraitVC { @@ -30,10 +31,12 @@ final class ResetPasswordVC: PortraitVC { private func configureHostingVC() { guard let environment = self.environment else { return } - let authRepository = AuthRepository() - let authUseCase = AuthUseCase(repository: authRepository) - let resetPasswordNicknameModel = ResetPasswordNicknameModel(authUseCase: authUseCase) - let hostingVC = UIHostingController(rootView: ResetPasswordNicknameView(model: resetPasswordNicknameModel).environmentObject(environment)) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let checkUsernameExitUseCase = CheckUsernameExitUseCsae(repository: repository) + let viewModel = ResetPasswordNicknameModel(checkUsenameExitUseCase: checkUsernameExitUseCase) + let hostingVC = UIHostingController(rootView: ResetPasswordNicknameView(model: viewModel).environmentObject(environment)) self.addChild(hostingVC) hostingVC.didMove(toParent: self) diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVC.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVC.swift index 4765529c..7efbb4d9 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVC.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya import MessageUI class SignupSigninVC: WhiteNavigationVC { @@ -316,10 +317,10 @@ extension SignupSigninVC { let password = self?.passwordTextField.textField.text else { return } if self?.viewModel.isSignin == true { - self?.viewModel.signin(info: TestUserSigninInfo(username: username, password: password)) + self?.viewModel.signin(request: TestUserSigninRequest(username: username, password: password)) } else { guard let email = self?.emailTextField.textField.text else { return } - self?.viewModel.signup(info: TestUserSignupInfo(username: username, email: email, password: password)) + self?.viewModel.signup(request: TestUserSignupRequest(username: username, email: email, password: password)) } }), for: .touchUpInside) @@ -513,8 +514,13 @@ import SwiftUI #Preview { UIViewControllerPreview { - let authUseCase = AuthUseCase(repository: AuthRepository()) - let viewModel = SignupSigninVM(authUseCase: authUseCase, isSignin: false) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = AuthRepository(api: api) + let signupUseCase = SignupUseCase(repository: repository) + let signinUseCase = SigninUseCase(repository: repository) + + let viewModel = SignupSigninVM(signupUseCase: signupUseCase, signinUseCase: signinUseCase, isSignin: false) return SignupSigninVC(viewModel: viewModel) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVM.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVM.swift index 4dd1c2e7..74bba9b5 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVM.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SignupSigninVM.swift @@ -10,68 +10,78 @@ import Foundation import Combine final class SignupSigninVM { - private let authUseCase: AuthUseCaseInterface + private let signupUseCase: SignupUseCase + private let signinUseCase: SigninUseCase let isSignin: Bool @Published var loadingText: String? @Published var alert: (title: String, text: String)? @Published var postable: Bool = false @Published var signinSuccess: Bool = false + // Combine binding + private var cancellables = Set() - init(authUseCase: AuthUseCaseInterface, - isSignin: Bool) { - self.authUseCase = authUseCase + init(signupUseCase: SignupUseCase, signinUseCase: SigninUseCase, isSignin: Bool) { + self.signupUseCase = signupUseCase + self.signinUseCase = signinUseCase self.isSignin = isSignin self.checkServerURL() } private func checkServerURL() { - NetworkURL.shared.updateServerURL { [weak self] in - if NetworkURL.shared.serverURL == nil { - self?.alert = (title: Localized.string(.Server_Popup_ServerCantUseTitle), text: Localized.string(.Server_Popup_ServerCantUseDesc)) + NetworkURL.shared.getServerURL() + .sink { [weak self] url in + if url == nil { + self?.alert = (title: Localized.string(.Server_Popup_ServerCantUseTitle), text: Localized.string(.Server_Popup_ServerCantUseDesc)) + } } - } + .store(in: &self.cancellables) + } - func signup(info: TestUserSignupInfo) { + func signup(request: TestUserSignupRequest) { self.loadingText = "Waiting for Signup..." - self.authUseCase.signup(signupInfo: info) { [weak self] result in - self?.loadingText = nil - switch result { - case .success(let token): - self?.saveUserInfo(username: info.username, password: info.password, token: token) - case .failure(let error): - switch error { - // signup 관련 error message 추가 - case .CLIENTERROR(_): - self?.alert = (title: Localized.string(.SignUp_Error_SignupError), text: Localized.string(.SignUp_Error_CheckNicknameOrEmail)) - default: - self?.alert = error.alertMessage + self.signupUseCase.execute(request: request) + .sink { [weak self] completion in + self?.loadingText = nil + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + switch networkError { + // signup 관련 error message 추가 + case .client(_): + self?.alert = (title: Localized.string(.SignUp_Error_SignupError), text: Localized.string(.SignUp_Error_CheckNicknameOrEmail)) + default: + self?.alert = networkError.alertMessage + } } + } receiveValue: { [weak self] authInfo in + self?.saveUserInfo(authInfo: authInfo, password: request.password) } - } + .store(in: &self.cancellables) } - func signin(info: TestUserSigninInfo) { + func signin(request: TestUserSigninRequest) { self.loadingText = "Waiting for Signin..." - self.authUseCase.signin(signinInfo: info) { [weak self] result in - self?.loadingText = nil - switch result { - case .success(let token): - self?.saveUserInfo(username: info.username, password: info.password, token: token) - case .failure(let error): - switch error { - // signin 관련 error message 추가 - case .CLIENTERROR(_): - self?.alert = (title: Localized.string(.SignIn_Error_SigninFail), text: Localized.string(.SignIn_Error_CheckNicknameOrPassword)) - // TestServer 에러핸들링 이슈로 404코드 추가 - case .NOTFOUND(_): - self?.alert = (title: Localized.string(.SignIn_Error_SigninFail), text: Localized.string(.SignIn_Error_CheckNicknameOrPassword)) - default: - self?.alert = error.alertMessage + self.signinUseCase.execute(request: request) + .sink { [weak self] completion in + self?.loadingText = nil + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + switch networkError { + // signin 관련 error message 추가 + case .client(_): + self?.alert = (title: Localized.string(.SignIn_Error_SigninFail), text: Localized.string(.SignIn_Error_CheckNicknameOrPassword)) + // TestServer 에러핸들링 이슈로 404코드 추가 + case .notFound(_): + self?.alert = (title: Localized.string(.SignIn_Error_SigninFail), text: Localized.string(.SignIn_Error_CheckNicknameOrPassword)) + default: + self?.alert = networkError.alertMessage + } } + } receiveValue: { [weak self] authInfo in + self?.saveUserInfo(authInfo: authInfo, password: request.password) } - } + .store(in: &self.cancellables) } func check(nickname: String?, email: String?, password: String?) { @@ -82,11 +92,11 @@ final class SignupSigninVM { } } - private func saveUserInfo(username: String, password: String, token: String) { + private func saveUserInfo(authInfo: AuthInfo, password: String) { // MARK: Token 저장, Noti signined - guard [KeyChain.shared.save(key: .username, value: username), + guard [KeyChain.shared.save(key: .username, value: authInfo.username), KeyChain.shared.save(key: .password, value: password), - KeyChain.shared.save(key: .token, value: token)].allSatisfy({ $0 }) == true else { + KeyChain.shared.save(key: .token, value: authInfo.token)].allSatisfy({ $0 }) == true else { self.alert = (title: "Keychain save fail", text: "") return } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVC.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVC.swift index 0eeca955..19052f52 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVC.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya final class SyncDailysVC: UIViewController { static let identifier = "SyncDailysVC" @@ -120,15 +121,26 @@ extension SyncDailysVC { extension SyncDailysVC { private func configureViewModel() { - let dailysUseCase = DailysUseCase(repository: DailysRepository()) - let recordTimesUseCase = RecordTimesUseCase(repository: RecordTimesRepository()) - let syncLogUseCase = SyncLogUseCase(repository: SyncLogRepository()) let targetDailys = self.syncDeviceStatusView.configureDailys() + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let dailyRepository = DailysRepository(api: api) + let recordTimeRepository = RecordTimesRepository(api: api) + let syncLogRepository = SyncLogRepository(api: api) + let getDailysUseCase = GetDailysUseCase(repository: dailyRepository) + let postDailysUseCase = PostDailysUseCase(repository: dailyRepository) + let getRecordTimeUseCase = GetRecordTimeUseCase(repository: recordTimeRepository) + let postRecordTimeUseCase = PostRecordTimeUseCase(repository: recordTimeRepository) + let getSyncLogUseCase = GetSyncLogUseCase(repository: syncLogRepository) + self.viewModel = SyncDailysVM( - dailysUseCase: dailysUseCase, - recordTimesUseCase: recordTimesUseCase, - syncLogUseCase: syncLogUseCase, - targetDailys: targetDailys) + getDailysUseCase: getDailysUseCase, + postDailysUseCase: postDailysUseCase, + getRecordTimeUseCase: getRecordTimeUseCase, + postRecordTimeUseCase: postRecordTimeUseCase, + getSyncLogUseCase: getSyncLogUseCase, + targetDailys: targetDailys + ) } } diff --git a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVM.swift b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVM.swift index 4894bdd6..d32197e6 100644 --- a/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVM.swift +++ b/Project_Timer/Present/Setting/Service/SettingTiTiLab/TestServer/SyncDailys/SyncDailysVM.swift @@ -10,37 +10,47 @@ import Foundation import Combine final class SyncDailysVM { - private let dailysUseCase: DailysUseCaseInterface - private let recordTimesUseCase: RecordTimesUseCaseInterface - private let syncLogUseCase: SyncLogUseCaseInterface + private let getDailysUseCase: GetDailysUseCase + private let postDailysUseCase: PostDailysUseCase + private let getRecordTimeUseCase: GetRecordTimeUseCase + private let postRecordTimeUseCase: PostRecordTimeUseCase + private let getSyncLogUseCase: GetSyncLogUseCase private var targetDailys: [Daily] @Published private(set) var syncLog: SyncLog? @Published private(set) var alert: (title: String, text: String)? @Published private(set) var loading: Bool = false @Published private(set) var saveDailysSuccess: Bool = false private(set) var loadingText: SyncDailysVC.LoadingStatus? + // Combine binding + private var cancellables = Set() - init(dailysUseCase: DailysUseCaseInterface, - recordTimesUseCase: RecordTimesUseCaseInterface, - syncLogUseCase: SyncLogUseCaseInterface, + init(getDailysUseCase: GetDailysUseCase, + postDailysUseCase: PostDailysUseCase, + getRecordTimeUseCase: GetRecordTimeUseCase, + postRecordTimeUseCase: PostRecordTimeUseCase, + getSyncLogUseCase: GetSyncLogUseCase, targetDailys: [Daily]) { - self.dailysUseCase = dailysUseCase - self.recordTimesUseCase = recordTimesUseCase - self.syncLogUseCase = syncLogUseCase + self.getDailysUseCase = getDailysUseCase + self.postDailysUseCase = postDailysUseCase self.targetDailys = targetDailys + self.getRecordTimeUseCase = getRecordTimeUseCase + self.postRecordTimeUseCase = postRecordTimeUseCase + self.getSyncLogUseCase = getSyncLogUseCase self.checkServerURL() } private func checkServerURL() { - NetworkURL.shared.updateServerURL { [weak self] in - if NetworkURL.shared.serverURL == nil { - self?.alert = (title: Localized.string(.Server_Popup_ServerCantUseTitle), text: Localized.string(.Server_Popup_ServerCantUseDesc)) - } else { - // fetch 서버 syncLog - self?.getSyncLog(afterUploaded: false) + NetworkURL.shared.getServerURL() + .sink { [weak self] url in + if url == nil { + self?.alert = (title: Localized.string(.Server_Popup_ServerCantUseTitle), text: Localized.string(.Server_Popup_ServerCantUseDesc)) + } else { + // fetch 서버 syncLog + self?.getSyncLog(afterUploaded: false) + } } - } + .store(in: &self.cancellables) } } @@ -72,23 +82,25 @@ extension SyncDailysVM { private func uploadDailys() { self.loadingText = .uploadDailys self.loading = true - self.dailysUseCase.uploadDailys(dailys: self.targetDailys) { [weak self] result in - self?.loading = false - switch result { - case .success(_): - self?.getDailys() - case .failure(let error): - switch error { - case .CLIENTERROR(let message): - if let message = message { - print("[upload Dailys ERROR] \(message)") + self.postDailysUseCase.execute(request: self.targetDailys) + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.loading = false + switch networkError { + case .client(let message): + if let message = message { + print("[upload Dailys ERROR] \(message)") + } + self?.alert = (title: Localized.string(.Server_Error_UploadError), text: Localized.string(.Server_Error_DecodeError)) + default: + self?.alert = networkError.alertMessage } - self?.alert = (title: Localized.string(.Server_Error_UploadError), text: Localized.string(.Server_Error_DecodeError)) - default: - self?.alert = error.alertMessage } + } receiveValue: { [weak self] _ in + self?.getDailys() } - } + .store(in: &self.cancellables) } /// uploadRecordTime -> getSyncLog 진행 @@ -96,23 +108,26 @@ extension SyncDailysVM { let recordTimes = RecordsManager.shared.recordTimes self.loadingText = .uploadRecordTime self.loading = true - self.recordTimesUseCase.uploadRecordTimes(recordTimes: recordTimes) { [weak self] result in - self?.loading = false - switch result { - case .success(_): - self?.getSyncLog(afterUploaded: true) - case .failure(let error): - switch error { - case .CLIENTERROR(let message): - if let message = message { - print("[upload Recordtime ERROR] \(message)") + self.postRecordTimeUseCase.execute(request: recordTimes) + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.loading = false + switch networkError { + case .client(let message): + if let message = message { + print("[upload Recordtime ERROR] \(message)") + } + self?.alert = (title: Localized.string(.Server_Error_UploadError), text: Localized.string(.Server_Error_DecodeError)) + default: + self?.alert = networkError.alertMessage } - self?.alert = (title: Localized.string(.Server_Error_UploadError), text: Localized.string(.Server_Error_DecodeError)) - default: - self?.alert = error.alertMessage } + } receiveValue: { [weak self] _ in + self?.loading = false + self?.getSyncLog(afterUploaded: true) } - } + .store(in: &self.cancellables) } } @@ -122,77 +137,85 @@ extension SyncDailysVM { private func getDailys() { self.loadingText = .getDailys self.loading = true - self.dailysUseCase.getDailys { [weak self] result in - switch result { - case .success(let dailys): + self.getDailysUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.loading = false + switch networkError { + case .client(let message): + if let message = message { + print("[get Dailys ERROR] \(message)") + } + self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) + default: + self?.alert = networkError.alertMessage + } + } + } receiveValue: { [weak self] dailys in self?.saveDailys(dailys) self?.loading = false self?.checkRecordTimes() - case .failure(let error): - self?.loading = false - switch error { - case .CLIENTERROR(let message): - if let message = message { - print("[get Dailys ERROR] \(message)") - } - self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) - default: - self?.alert = error.alertMessage - } } - } + .store(in: &self.cancellables) } /// getRecordTime -> getSyncLog 진행 private func getRecordtime() { self.loadingText = .getRecordTime self.loading = true - self.recordTimesUseCase.getRecordTimes { [weak self] result in - switch result { - case .success(let recordTimes): + self.getRecordTimeUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.loading = false + switch networkError { + case .client(let message): + if let message = message { + print("[get RecordTimes ERROR] \(message)") + } + self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) + default: + self?.alert = networkError.alertMessage + } + } + } receiveValue: { [weak self] recordTimes in self?.saveRecordTimes(recordTimes) self?.loading = false self?.getSyncLog(afterUploaded: true) - case .failure(let error): - switch error { - case .CLIENTERROR(let message): - if let message = message { - print("[get RecordTimes ERROR] \(message)") - } - self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) - default: - self?.alert = error.alertMessage - } } - } + .store(in: &self.cancellables) } /// sync 로직 후 getSyncLog, 또는 화면진입시 진행 private func getSyncLog(afterUploaded: Bool) { self.loadingText = .getSyncLog self.loading = true - self.syncLogUseCase.getSyncLog { [weak self] result in - self?.loading = false - switch result { - case .success(let syncLog): - if let syncLog = syncLog, afterUploaded { + self.getSyncLogUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.loading = false + switch networkError { + case .client(let message): + if let message = message { + print("[get SyncLog ERROR] \(message)") + } + self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) + default: + self?.alert = networkError.alertMessage + } + } + } receiveValue: { [weak self] syncLog in + self?.loading = false + if afterUploaded { self?.saveLastUploadedDate(to: syncLog.updatedAt) self?.targetDailys = [] self?.saveDailysSuccess = true } self?.syncLog = syncLog - case .failure(let error): - switch error { - case .CLIENTERROR(let message): - if let message = message { - print("[get SyncLog ERROR] \(message)") - } - self?.alert = (title: Localized.string(.Server_Error_DownloadError), text: Localized.string(.Server_Error_DecodeError)) - default: - self?.alert = error.alertMessage - } } - } + .store(in: &self.cancellables) } } @@ -226,7 +249,12 @@ extension SyncDailysVM { let dailyStartAt = lastDaily.taskHistorys?.values .flatMap({ $0 }) .sorted(by: { $0.endDate < $1.endDate }) - .last?.startDate else { return } + .last?.startDate else { + // 정보가 없는 경우 + self.getSyncLog(afterUploaded: true) + return + } + let localStartAt = RecordsManager.shared.recordTimes.recordStartAt if (dailyStartAt.YYYYMMDDHMSstyleString == localStartAt.YYYYMMDDHMSstyleString) { diff --git a/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVC.swift b/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVC.swift index 97a5adec..7e545271 100644 --- a/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVC.swift +++ b/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVC.swift @@ -8,6 +8,7 @@ import UIKit import Combine +import Moya final class SettingUpdateHistoryVC: UIViewController { static let identifier = "SettingUpdateHistoryVC" @@ -58,9 +59,12 @@ extension SettingUpdateHistoryVC { } private func configureViewModel() { - // MARK: NetworkController 주입 고민이 필요 - let networkController = NetworkController(network: Network()) - self.viewModel = SettingUpdateHistoryVM(networkController: networkController) + // TODO: DI 수정 + let api = TTProvider(session: Session(interceptor: NetworkInterceptor.shared)) + let repository = FirebaseRepository(api: api) + let getUpdateHistorysUseCase = GetUpdateHistorysUseCase(repository: repository) + + self.viewModel = SettingUpdateHistoryVM(getUpdateHistorysUseCase: getUpdateHistorysUseCase) } private func stopLoader() { diff --git a/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVM.swift b/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVM.swift index 04f131e6..2bc8f98e 100644 --- a/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVM.swift +++ b/Project_Timer/Present/Setting/UpdateHistory/SettingUpdateHistoryVM.swift @@ -10,25 +10,29 @@ import Foundation import Combine final class SettingUpdateHistoryVM { - let networkController: UpdateHistoryFetchable - @Published private(set) var infos: [UpdateInfo] = [] + let getUpdateHistorysUseCase: GetUpdateHistorysUseCase + @Published private(set) var infos: [UpdateHistoryInfo] = [] @Published private(set) var warning: (title: String, text: String)? + // Combine binding + private var cancellables = Set() - init(networkController: UpdateHistoryFetchable) { - self.networkController = networkController + init(getUpdateHistorysUseCase: GetUpdateHistorysUseCase) { + self.getUpdateHistorysUseCase = getUpdateHistorysUseCase self.configureInfos() } private func configureInfos() { - self.networkController.getUpdateHistorys { [weak self] result in - switch result { - case .success(let updateInfo): - self?.infos = updateInfo.sorted(by: { + self.getUpdateHistorysUseCase.execute() + .sink { [weak self] completion in + if case .failure(let networkError) = completion { + print("ERROR", #function, networkError) + self?.warning = networkError.alertMessage + } + } receiveValue: { [weak self] updateHistoryInfos in + self?.infos = updateHistoryInfos.sorted(by: { $0.version.value.compare($1.version.value, options: .numeric) == .orderedDescending }) - case .failure(let error): - self?.warning = error.alertMessage } - } + .store(in: &self.cancellables) } } diff --git a/Project_Timer/Present/Setting/UpdateHistory/UpdateInfoCell.swift b/Project_Timer/Present/Setting/UpdateHistory/UpdateInfoCell.swift index 7b4b3e45..4ad51ece 100644 --- a/Project_Timer/Present/Setting/UpdateHistory/UpdateInfoCell.swift +++ b/Project_Timer/Present/Setting/UpdateHistory/UpdateInfoCell.swift @@ -15,7 +15,7 @@ final class UpdateInfoCell: UICollectionViewCell { @IBOutlet weak var dateLabel: UILabel! @IBOutlet weak var textLabel: UILabel! - func configure(with info: UpdateInfo, superWidth: CGFloat) { + func configure(with info: UpdateHistoryInfo, superWidth: CGFloat) { self.versionLabel.text = "ver \(info.version.value)" self.dateLabel.text = "\(info.date.value)" self.textLabel.text = info.text.value