diff --git a/Helfy.xcodeproj/project.pbxproj b/Helfy.xcodeproj/project.pbxproj index 6fa446a..ee6a483 100644 --- a/Helfy.xcodeproj/project.pbxproj +++ b/Helfy.xcodeproj/project.pbxproj @@ -12,14 +12,21 @@ 26094C042AD87943000AAD3B /* WriteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26094C032AD87943000AAD3B /* WriteView.swift */; }; 26094C072AD87971000AAD3B /* WriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26094C062AD87971000AAD3B /* WriteViewController.swift */; }; 26094C0A2ADC3E9E000AAD3B /* WriteModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26094C092ADC3E9E000AAD3B /* WriteModel.swift */; }; + 2658C0312B77FFFB002099FC /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C0302B77FFFB002099FC /* SearchViewController.swift */; }; + 2658C0492B7A21AE002099FC /* CategoryPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C0482B7A21AE002099FC /* CategoryPageView.swift */; }; + 2658C04B2B7A21C9002099FC /* CategoryPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C04A2B7A21C9002099FC /* CategoryPageModel.swift */; }; + 2658C04D2B7A21F2002099FC /* CategoryPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C04C2B7A21F2002099FC /* CategoryPageViewController.swift */; }; + 2658C04F2B7A2249002099FC /* CategoryPageAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C04E2B7A2249002099FC /* CategoryPageAPIHandler.swift */; }; + 2658C0512B7A2269002099FC /* ImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2658C0502B7A2269002099FC /* ImageLoader.swift */; }; + 26C2ACB22B77840B00E07CA2 /* BannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26C2ACB12B77840B00E07CA2 /* BannerView.swift */; }; + 26C2ACB42B77841B00E07CA2 /* BannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26C2ACB32B77841B00E07CA2 /* BannerViewController.swift */; }; 26EA7E4C2AD1540300FFE7ED /* ReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EA7E4B2AD1540300FFE7ED /* ReportViewController.swift */; }; 2A2E02E32AD54D970026C495 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2E02E22AD54D970026C495 /* LoginViewController.swift */; }; 2A2E02E62AD5510F0026C495 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2A2E02E52AD5510F0026C495 /* GoogleService-Info.plist */; }; 2A2E02E82AD5551C0026C495 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 2A74D6792ADD2CBB00800E9E /* FirebaseAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A74D6782ADD2CBB00800E9E /* FirebaseAuth.swift */; }; 2A8304742B176BB300979B23 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A8304732B176BB300979B23 /* MainViewController.swift */; }; - 2A99A2652AD681DB0090155C /* QuizView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A99A2642AD681DB0090155C /* QuizView.swift */; }; - 2A99A2672AD682050090155C /* QuizeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A99A2662AD682050090155C /* QuizeModel.swift */; }; + 2A99A2652AD681DB0090155C /* QuizHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A99A2642AD681DB0090155C /* QuizHomeView.swift */; }; 2A99A2692AD6882F0090155C /* ReportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A99A2682AD6882F0090155C /* ReportView.swift */; }; 2A99A26B2AD688660090155C /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A99A26A2AD688660090155C /* TextView.swift */; }; 2AFC98AE2ACD4A2100AB349D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AFC98AD2ACD4A2100AB349D /* AppDelegate.swift */; }; @@ -34,27 +41,43 @@ 2AFC98E72ACD4DB700AB349D /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */ = {isa = PBXBuildFile; productRef = 2AFC98E62ACD4DB700AB349D /* FirebaseAnalyticsWithoutAdIdSupport */; }; 2AFC98E92ACD4DB700AB349D /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 2AFC98E82ACD4DB700AB349D /* FirebaseAppCheck */; }; 2AFDABE22AFF8E0200A8E19C /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 2AFDABE12AFF8E0200A8E19C /* FirebaseAuth */; }; - 2AFDABEC2B0498A000A8E19C /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AFDABEB2B04989F00A8E19C /* UserModel.swift */; }; - + C1154CDE2B30A2A600EB767E /* QuizTobBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CDD2B30A2A600EB767E /* QuizTobBarViewController.swift */; }; + C1154CE02B3C0B6B00EB767E /* QuizModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CDF2B3C0B6B00EB767E /* QuizModel.swift */; }; + C1154CE22B459E8100EB767E /* QuizAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CE12B459E8100EB767E /* QuizAPIHandler.swift */; }; + C1154CE52B46C8A000EB767E /* TodayQuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CE42B46C8A000EB767E /* TodayQuizViewController.swift */; }; + C1154CE72B46C8B200EB767E /* DoQuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CE62B46C8B100EB767E /* DoQuizViewController.swift */; }; + C1154CE92B46C8C500EB767E /* WrongQuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CE82B46C8C500EB767E /* WrongQuizViewController.swift */; }; + C10FC4542B70635D00356F1B /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10FC4532B70635D00356F1B /* MainView.swift */; }; + C10FC4562B70AD7900356F1B /* MainModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10FC4552B70AD7900356F1B /* MainModel.swift */; }; + C10FC45A2B70ADF800356F1B /* MainAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10FC4592B70ADF800356F1B /* MainAPIHandler.swift */; }; + C13470C52B6A043700626442 /* MyPageAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13470C42B6A043700626442 /* MyPageAPIHandler.swift */; }; + C13470C72B6A0CCF00626442 /* EditModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13470C62B6A0CCF00626442 /* EditModalViewController.swift */; }; + C1154CEB2B4A5F6600EB767E /* QuizHomeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CEA2B4A5F6600EB767E /* QuizHomeModel.swift */; }; + C1154CED2B4AD28000EB767E /* CorrectOrWrongViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1154CEC2B4AD28000EB767E /* CorrectOrWrongViewController.swift */; }; C141B8FB2AFB49D10000FFA8 /* MypageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C141B8FA2AFB49D10000FFA8 /* MypageView.swift */; }; C141B8FD2AFB4A750000FFA8 /* MypageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C141B8FC2AFB4A750000FFA8 /* MypageModel.swift */; }; C141B8FF2AFB4AC80000FFA8 /* MypageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C141B8FE2AFB4AC80000FFA8 /* MypageViewController.swift */; }; - C1735B3C2AD03F61002FFB77 /* QuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1735B3B2AD03F61002FFB77 /* QuizViewController.swift */; }; + C1735B3C2AD03F61002FFB77 /* QuizHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1735B3B2AD03F61002FFB77 /* QuizHomeViewController.swift */; }; C1735B3E2AD042E5002FFB77 /* RankingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1735B3D2AD042E5002FFB77 /* RankingView.swift */; }; C1735B422AD04532002FFB77 /* RankingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1735B412AD04532002FFB77 /* RankingModel.swift */; }; + C173D3D32B1874CC00F72A86 /* CategoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C173D3D22B1874CC00F72A86 /* CategoryView.swift */; }; + C173D3D52B18751100F72A86 /* CategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C173D3D42B18751100F72A86 /* CategoryViewController.swift */; }; C173D42C2B19E62700F72A86 /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = C173D42B2B19E62700F72A86 /* GoogleSignIn */; }; C173D42E2B19E62700F72A86 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = C173D42D2B19E62700F72A86 /* GoogleSignInSwift */; }; C1CF0F322AED41270052EC8F /* BottomTabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF0F312AED41270052EC8F /* BottomTabBarView.swift */; }; C1CF0F342AED472F0052EC8F /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF0F332AED472F0052EC8F /* TabBarViewController.swift */; }; C1CF0F362AEFA9E70052EC8F /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF0F352AEFA9E70052EC8F /* HomeViewController.swift */; }; C1CF0F382AEFAA2C0052EC8F /* CommunityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF0F372AEFAA2C0052EC8F /* CommunityViewController.swift */; }; + C1F638E42B0DD24700D4F8C8 /* QuizView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638E32B0DD24700D4F8C8 /* QuizView.swift */; }; + C1F638E82B0DD27D00D4F8C8 /* QuizViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638E72B0DD27D00D4F8C8 /* QuizViewController.swift */; }; + C1E521412B81ECEB0055D8BE /* CategoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E521402B81ECEB0055D8BE /* CategoryModel.swift */; }; + C1E521432B81ED190055D8BE /* CategoryAPIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E521422B81ED190055D8BE /* CategoryAPIHandler.swift */; }; C1F638E42B0DD24700D4F8C8 /* QuestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638E32B0DD24700D4F8C8 /* QuestionView.swift */; }; C1F638E62B0DD26600D4F8C8 /* QuestionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638E52B0DD26600D4F8C8 /* QuestionModel.swift */; }; C1F638E82B0DD27D00D4F8C8 /* QuestionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638E72B0DD27D00D4F8C8 /* QuestionViewController.swift */; }; C1F638EC2B0F483100D4F8C8 /* ChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638EB2B0F483100D4F8C8 /* ChoiceView.swift */; }; - C1F638EE2B0F484100D4F8C8 /* MultipleChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638ED2B0F484100D4F8C8 /* MultipleChoiceView.swift */; }; - C1F638F02B0F485000D4F8C8 /* TrueOrFalseQuestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638EF2B0F485000D4F8C8 /* TrueOrFalseQuestionView.swift */; }; + C1F638F02B0F485000D4F8C8 /* TrueOrFalseQuizView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F638EF2B0F485000D4F8C8 /* TrueOrFalseQuizView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -80,13 +103,20 @@ 26094C032AD87943000AAD3B /* WriteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteView.swift; sourceTree = ""; }; 26094C062AD87971000AAD3B /* WriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteViewController.swift; sourceTree = ""; }; 26094C092ADC3E9E000AAD3B /* WriteModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteModel.swift; sourceTree = ""; }; + 2658C0302B77FFFB002099FC /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = ""; }; + 2658C0482B7A21AE002099FC /* CategoryPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPageView.swift; sourceTree = ""; }; + 2658C04A2B7A21C9002099FC /* CategoryPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPageModel.swift; sourceTree = ""; }; + 2658C04C2B7A21F2002099FC /* CategoryPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPageViewController.swift; sourceTree = ""; }; + 2658C04E2B7A2249002099FC /* CategoryPageAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPageAPIHandler.swift; sourceTree = ""; }; + 2658C0502B7A2269002099FC /* ImageLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageLoader.swift; sourceTree = ""; }; + 26C2ACB12B77840B00E07CA2 /* BannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerView.swift; sourceTree = ""; }; + 26C2ACB32B77841B00E07CA2 /* BannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerViewController.swift; sourceTree = ""; }; 26EA7E4B2AD1540300FFE7ED /* ReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewController.swift; sourceTree = ""; }; 2A2E02E22AD54D970026C495 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; 2A2E02E52AD5510F0026C495 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 2A74D6782ADD2CBB00800E9E /* FirebaseAuth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAuth.swift; sourceTree = ""; }; 2A8304732B176BB300979B23 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 2A99A2642AD681DB0090155C /* QuizView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizView.swift; sourceTree = ""; }; - 2A99A2662AD682050090155C /* QuizeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizeModel.swift; sourceTree = ""; }; + 2A99A2642AD681DB0090155C /* QuizHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizHomeView.swift; sourceTree = ""; }; 2A99A2682AD6882F0090155C /* ReportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportView.swift; sourceTree = ""; }; 2A99A26A2AD688660090155C /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = ""; }; 2AFC98AA2ACD4A2100AB349D /* Helfy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Helfy.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -102,22 +132,40 @@ 2AFC98D02ACD4A3500AB349D /* HelfyUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelfyUITestsLaunchTests.swift; sourceTree = ""; }; 2AFDABE02AFF8B3400A8E19C /* Helfy.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Helfy.entitlements; sourceTree = ""; }; 2AFDABEB2B04989F00A8E19C /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; + C1154CDD2B30A2A600EB767E /* QuizTobBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = QuizTobBarViewController.swift; path = "../../../../.Trash/참고4/Helfy-iOS/Helfy/Controller/QuizTobBarViewController.swift"; sourceTree = ""; }; + C1154CDF2B3C0B6B00EB767E /* QuizModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizModel.swift; sourceTree = ""; }; + C1154CE12B459E8100EB767E /* QuizAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizAPIHandler.swift; sourceTree = ""; }; + C1154CE42B46C8A000EB767E /* TodayQuizViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayQuizViewController.swift; sourceTree = ""; }; + C1154CE62B46C8B100EB767E /* DoQuizViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoQuizViewController.swift; sourceTree = ""; }; + C1154CE82B46C8C500EB767E /* WrongQuizViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrongQuizViewController.swift; sourceTree = ""; }; + C1154CEA2B4A5F6600EB767E /* QuizHomeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizHomeModel.swift; sourceTree = ""; }; + C1154CEC2B4AD28000EB767E /* CorrectOrWrongViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectOrWrongViewController.swift; sourceTree = ""; }; + C10FC4532B70635D00356F1B /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; + C10FC4552B70AD7900356F1B /* MainModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainModel.swift; sourceTree = ""; }; + C10FC4592B70ADF800356F1B /* MainAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAPIHandler.swift; sourceTree = ""; }; + C13470C42B6A043700626442 /* MyPageAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAPIHandler.swift; sourceTree = ""; }; + C13470C62B6A0CCF00626442 /* EditModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditModalViewController.swift; sourceTree = ""; }; C141B8FA2AFB49D10000FFA8 /* MypageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MypageView.swift; sourceTree = ""; }; C141B8FC2AFB4A750000FFA8 /* MypageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MypageModel.swift; sourceTree = ""; }; C141B8FE2AFB4AC80000FFA8 /* MypageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MypageViewController.swift; sourceTree = ""; }; - C1735B3B2AD03F61002FFB77 /* QuizViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizViewController.swift; sourceTree = ""; }; + C1735B3B2AD03F61002FFB77 /* QuizHomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizHomeViewController.swift; sourceTree = ""; }; C1735B3D2AD042E5002FFB77 /* RankingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingView.swift; sourceTree = ""; }; C1735B412AD04532002FFB77 /* RankingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankingModel.swift; sourceTree = ""; }; + C173D3D22B1874CC00F72A86 /* CategoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryView.swift; sourceTree = ""; }; + C173D3D42B18751100F72A86 /* CategoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryViewController.swift; sourceTree = ""; }; C1CF0F312AED41270052EC8F /* BottomTabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomTabBarView.swift; sourceTree = ""; }; C1CF0F332AED472F0052EC8F /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = ""; }; C1CF0F352AEFA9E70052EC8F /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; C1CF0F372AEFAA2C0052EC8F /* CommunityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityViewController.swift; sourceTree = ""; }; + C1F638E32B0DD24700D4F8C8 /* QuizView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizView.swift; sourceTree = ""; }; + C1F638E72B0DD27D00D4F8C8 /* QuizViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizViewController.swift; sourceTree = ""; }; + C1E521402B81ECEB0055D8BE /* CategoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryModel.swift; sourceTree = ""; }; + C1E521422B81ED190055D8BE /* CategoryAPIHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryAPIHandler.swift; sourceTree = ""; }; C1F638E32B0DD24700D4F8C8 /* QuestionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionView.swift; sourceTree = ""; }; C1F638E52B0DD26600D4F8C8 /* QuestionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionModel.swift; sourceTree = ""; }; C1F638E72B0DD27D00D4F8C8 /* QuestionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionViewController.swift; sourceTree = ""; }; C1F638EB2B0F483100D4F8C8 /* ChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceView.swift; sourceTree = ""; }; - C1F638ED2B0F484100D4F8C8 /* MultipleChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleChoiceView.swift; sourceTree = ""; }; - C1F638EF2B0F485000D4F8C8 /* TrueOrFalseQuestionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrueOrFalseQuestionView.swift; sourceTree = ""; }; + C1F638EF2B0F485000D4F8C8 /* TrueOrFalseQuizView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrueOrFalseQuizView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -132,11 +180,8 @@ 2AFC98E32ACD4DB700AB349D /* FirebaseAnalyticsOnDeviceConversion in Frameworks */, 2AFC98E92ACD4DB700AB349D /* FirebaseAppCheck in Frameworks */, 2AFC98E72ACD4DB700AB349D /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */, - - 2A2E02E82AD5551C0026C495 /* GoogleSignIn in Frameworks */, - 2A2E02E82AD5551C0026C495 /* (null) in Frameworks */, - + 2A2E02E82AD5551C0026C495 /* (null) in Frameworks */, 2AFDABE22AFF8E0200A8E19C /* FirebaseAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -170,8 +215,9 @@ 2AB9D1422ACFF42B00686F83 /* Controller */ = { isa = PBXGroup; children = ( + C1154CE32B46C68500EB767E /* Quiz */, 2A74D6752ADD2C3300800E9E /* Login */, - C1735B3B2AD03F61002FFB77 /* QuizViewController.swift */, + C1735B3B2AD03F61002FFB77 /* QuizHomeViewController.swift */, 26EA7E4B2AD1540300FFE7ED /* ReportViewController.swift */, C1CF0F332AED472F0052EC8F /* TabBarViewController.swift */, C1CF0F352AEFA9E70052EC8F /* HomeViewController.swift */, @@ -180,7 +226,15 @@ 26094C062AD87971000AAD3B /* WriteViewController.swift */, 2A8304732B176BB300979B23 /* MainViewController.swift */, C141B8FE2AFB4AC80000FFA8 /* MypageViewController.swift */, + C1154CDD2B30A2A600EB767E /* QuizTobBarViewController.swift */, + C1F638E72B0DD27D00D4F8C8 /* QuizViewController.swift */, + C1154CEC2B4AD28000EB767E /* CorrectOrWrongViewController.swift */, + C13470C62B6A0CCF00626442 /* EditModalViewController.swift */, C1F638E72B0DD27D00D4F8C8 /* QuestionViewController.swift */, + C173D3D42B18751100F72A86 /* CategoryViewController.swift */, + 26C2ACB32B77841B00E07CA2 /* BannerViewController.swift */, + 2658C0302B77FFFB002099FC /* SearchViewController.swift */, + 2658C04C2B7A21F2002099FC /* CategoryPageViewController.swift */, ); path = Controller; sourceTree = ""; @@ -213,12 +267,15 @@ C1735B342ACFFB57002FFB77 /* View */, C1735B332ACFFB46002FFB77 /* Model */, 2AB9D1422ACFF42B00686F83 /* Controller */, + C10FC4582B70ADA500356F1B /* APIHandler */, 2AFC98AD2ACD4A2100AB349D /* AppDelegate.swift */, 2AFC98AF2ACD4A2100AB349D /* SceneDelegate.swift */, + C13470C42B6A043700626442 /* MyPageAPIHandler.swift */, 2AFC98B62ACD4A3400AB349D /* Assets.xcassets */, 2AFC98B82ACD4A3400AB349D /* LaunchScreen.storyboard */, 2AFC98BB2ACD4A3400AB349D /* Info.plist */, 2A2E02E52AD5510F0026C495 /* GoogleService-Info.plist */, + C1154CE12B459E8100EB767E /* QuizAPIHandler.swift */, ); path = Helfy; sourceTree = ""; @@ -240,6 +297,30 @@ path = HelfyUITests; sourceTree = ""; }; + C1154CE32B46C68500EB767E /* Quiz */ = { + isa = PBXGroup; + children = ( + C1735B3B2AD03F61002FFB77 /* QuizHomeViewController.swift */, + C1F638E72B0DD27D00D4F8C8 /* QuizViewController.swift */, + C1154CE42B46C8A000EB767E /* TodayQuizViewController.swift */, + C1154CE62B46C8B100EB767E /* DoQuizViewController.swift */, + C1154CE82B46C8C500EB767E /* WrongQuizViewController.swift */, + C1154CEC2B4AD28000EB767E /* CorrectOrWrongViewController.swift */, + ); + path = Quiz; + sourceTree = ""; + }; + C10FC4582B70ADA500356F1B /* APIHandler */ = { + isa = PBXGroup; + children = ( + C10FC4592B70ADF800356F1B /* MainAPIHandler.swift */, + 2658C04E2B7A2249002099FC /* CategoryPageAPIHandler.swift */, + 2658C0502B7A2269002099FC /* ImageLoader.swift */, + C1E521422B81ED190055D8BE /* CategoryAPIHandler.swift */, + ); + path = APIHandler; + sourceTree = ""; + }; C141B8F72AFB44910000FFA8 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -251,11 +332,14 @@ isa = PBXGroup; children = ( C1735B412AD04532002FFB77 /* RankingModel.swift */, - 2A99A2662AD682050090155C /* QuizeModel.swift */, 26094C092ADC3E9E000AAD3B /* WriteModel.swift */, 2AFDABEB2B04989F00A8E19C /* UserModel.swift */, C141B8FC2AFB4A750000FFA8 /* MypageModel.swift */, - C1F638E52B0DD26600D4F8C8 /* QuestionModel.swift */, + C1154CDF2B3C0B6B00EB767E /* QuizModel.swift */, + C1154CEA2B4A5F6600EB767E /* QuizHomeModel.swift */, + C10FC4552B70AD7900356F1B /* MainModel.swift */, + 2658C04A2B7A21C9002099FC /* CategoryPageModel.swift */, + C1E521402B81ECEB0055D8BE /* CategoryModel.swift */, ); path = Model; sourceTree = ""; @@ -263,8 +347,9 @@ C1735B342ACFFB57002FFB77 /* View */ = { isa = PBXGroup; children = ( + C1F638EA2B0F481200D4F8C8 /* Quiz */, C1F638EA2B0F481200D4F8C8 /* Question */, - 2A99A2642AD681DB0090155C /* QuizView.swift */, + 2A99A2642AD681DB0090155C /* QuizHomeView.swift */, C1735B3D2AD042E5002FFB77 /* RankingView.swift */, 2A99A2682AD6882F0090155C /* ReportView.swift */, 2A99A26A2AD688660090155C /* TextView.swift */, @@ -272,19 +357,21 @@ 26094BFA2AD69724000AAD3B /* NaviButtonView.swift */, 26094C032AD87943000AAD3B /* WriteView.swift */, C141B8FA2AFB49D10000FFA8 /* MypageView.swift */, + C10FC4532B70635D00356F1B /* MainView.swift */, + C173D3D22B1874CC00F72A86 /* CategoryView.swift */, + 26C2ACB12B77840B00E07CA2 /* BannerView.swift */, + 2658C0482B7A21AE002099FC /* CategoryPageView.swift */, ); path = View; sourceTree = ""; }; - C1F638EA2B0F481200D4F8C8 /* Question */ = { + C1F638EA2B0F481200D4F8C8 /* Quiz */ = { isa = PBXGroup; children = ( - C1F638E32B0DD24700D4F8C8 /* QuestionView.swift */, - C1F638EB2B0F483100D4F8C8 /* ChoiceView.swift */, - C1F638ED2B0F484100D4F8C8 /* MultipleChoiceView.swift */, - C1F638EF2B0F485000D4F8C8 /* TrueOrFalseQuestionView.swift */, + 2A99A2642AD681DB0090155C /* QuizHomeView.swift */, + C1F638E32B0DD24700D4F8C8 /* QuizView.swift */, ); - path = Question; + path = Quiz; sourceTree = ""; }; /* End PBXGroup section */ @@ -432,40 +519,66 @@ buildActionMask = 2147483647; files = ( C141B8FF2AFB4AC80000FFA8 /* MypageViewController.swift in Sources */, + 2658C0512B7A2269002099FC /* ImageLoader.swift in Sources */, 26094BFB2AD69724000AAD3B /* NaviButtonView.swift in Sources */, + C1154CED2B4AD28000EB767E /* CorrectOrWrongViewController.swift in Sources */, C1735B422AD04532002FFB77 /* RankingModel.swift in Sources */, - 2A99A2652AD681DB0090155C /* QuizView.swift in Sources */, + 2A99A2652AD681DB0090155C /* QuizHomeView.swift in Sources */, C141B8FB2AFB49D10000FFA8 /* MypageView.swift in Sources */, + C1154CEB2B4A5F6600EB767E /* QuizHomeModel.swift in Sources */, + 26C2ACB42B77841B00E07CA2 /* BannerViewController.swift in Sources */, 26094C072AD87971000AAD3B /* WriteViewController.swift in Sources */, 2A99A2672AD682050090155C /* QuizeModel.swift in Sources */, + 2658C0492B7A21AE002099FC /* CategoryPageView.swift in Sources */, C1F638EC2B0F483100D4F8C8 /* ChoiceView.swift in Sources */, + C1F638E42B0DD24700D4F8C8 /* QuizView.swift in Sources */, C1F638E62B0DD26600D4F8C8 /* QuestionModel.swift in Sources */, C1F638E42B0DD24700D4F8C8 /* QuestionView.swift in Sources */, + C1E521412B81ECEB0055D8BE /* CategoryModel.swift in Sources */, C1F638EE2B0F484100D4F8C8 /* MultipleChoiceView.swift in Sources */, + C13470C52B6A043700626442 /* MyPageAPIHandler.swift in Sources */, C1735B3E2AD042E5002FFB77 /* RankingView.swift in Sources */, 2A8304742B176BB300979B23 /* MainViewController.swift in Sources */, + C1154CE22B459E8100EB767E /* QuizAPIHandler.swift in Sources */, C1CF0F342AED472F0052EC8F /* TabBarViewController.swift in Sources */, C141B8FD2AFB4A750000FFA8 /* MypageModel.swift in Sources */, C1CF0F362AEFA9E70052EC8F /* HomeViewController.swift in Sources */, + C1154CE92B46C8C500EB767E /* WrongQuizViewController.swift in Sources */, + C1154CE72B46C8B200EB767E /* DoQuizViewController.swift in Sources */, + C1154CE02B3C0B6B00EB767E /* QuizModel.swift in Sources */, C1CF0F322AED41270052EC8F /* BottomTabBarView.swift in Sources */, 2A2E02E32AD54D970026C495 /* LoginViewController.swift in Sources */, 2AFDABEC2B0498A000A8E19C /* UserModel.swift in Sources */, + 26C2ACB22B77840B00E07CA2 /* BannerView.swift in Sources */, C1CF0F382AEFAA2C0052EC8F /* CommunityViewController.swift in Sources */, + C173D3D52B18751100F72A86 /* CategoryViewController.swift in Sources */, 26094C0A2ADC3E9E000AAD3B /* WriteModel.swift in Sources */, + C1154CDE2B30A2A600EB767E /* QuizTobBarViewController.swift in Sources */, 26094C042AD87943000AAD3B /* WriteView.swift in Sources */, + C10FC45A2B70ADF800356F1B /* MainAPIHandler.swift in Sources */, 2A99A2692AD6882F0090155C /* ReportView.swift in Sources */, 2A74D6792ADD2CBB00800E9E /* FirebaseAuth.swift in Sources */, - + C1F638F02B0F485000D4F8C8 /* TrueOrFalseQuizView.swift in Sources */, C1F638F02B0F485000D4F8C8 /* TrueOrFalseQuestionView.swift in Sources */, - 2A74D6772ADD2C4300800E9E /* GoogleSignIn.swift in Sources */, - 2AFC98AE2ACD4A2100AB349D /* AppDelegate.swift in Sources */, + C1154CE52B46C8A000EB767E /* TodayQuizViewController.swift in Sources */, 26094C022AD87577000AAD3B /* NavigationController.swift in Sources */, + C10FC4542B70635D00356F1B /* MainView.swift in Sources */, 26EA7E4C2AD1540300FFE7ED /* ReportViewController.swift in Sources */, + C1E521432B81ED190055D8BE /* CategoryAPIHandler.swift in Sources */, 2A99A26B2AD688660090155C /* TextView.swift in Sources */, + C1F638E82B0DD27D00D4F8C8 /* QuizViewController.swift in Sources */, + C1735B3C2AD03F61002FFB77 /* QuizHomeViewController.swift in Sources */, + 2658C04F2B7A2249002099FC /* CategoryPageAPIHandler.swift in Sources */, C1F638E82B0DD27D00D4F8C8 /* QuestionViewController.swift in Sources */, + 2658C0312B77FFFB002099FC /* SearchViewController.swift in Sources */, + C10FC4562B70AD7900356F1B /* MainModel.swift in Sources */, + 2658C04D2B7A21F2002099FC /* CategoryPageViewController.swift in Sources */, C1735B3C2AD03F61002FFB77 /* QuizViewController.swift in Sources */, + C13470C72B6A0CCF00626442 /* EditModalViewController.swift in Sources */, 2AFC98B02ACD4A2100AB349D /* SceneDelegate.swift in Sources */, + 2658C04B2B7A21C9002099FC /* CategoryPageModel.swift in Sources */, + C173D3D32B1874CC00F72A86 /* CategoryView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -657,7 +770,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.hanni.Helfy; + PRODUCT_BUNDLE_IDENTIFIER = com.hanni.helfy; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Helfy; @@ -690,7 +803,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.hanni.Helfy; + PRODUCT_BUNDLE_IDENTIFIER = com.hanni.helfy; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Helfy; @@ -875,7 +988,6 @@ package = 2AFC98DF2ACD4DB700AB349D /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseAuth; }; - C173D42B2B19E62700F72A86 /* GoogleSignIn */ = { isa = XCSwiftPackageProductDependency; package = C11E8BFB2AD68A230073C17F /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; @@ -886,7 +998,6 @@ package = C11E8BFB2AD68A230073C17F /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; productName = GoogleSignInSwift; }; - /* End XCSwiftPackageProductDependency section */ }; rootObject = 2AFC98A22ACD4A2100AB349D /* Project object */; diff --git a/Helfy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Helfy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 56e318c..0000000 --- a/Helfy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,140 +0,0 @@ -{ - "pins" : [ - { - "identity" : "abseil-cpp-binary", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/abseil-cpp-binary.git", - "state" : { - "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", - "version" : "1.2022062300.0" - } - }, - { - "identity" : "appauth-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/openid/AppAuth-iOS.git", - "state" : { - "revision" : "71cde449f13d453227e687458144bde372d30fc7", - "version" : "1.6.2" - } - }, - { - "identity" : "firebase-ios-sdk", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/firebase-ios-sdk", - "state" : { - "revision" : "837d4af6ead57cec1fc38007892500d3139c7556", - "version" : "10.16.0" - } - }, - { - "identity" : "googleappmeasurement", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleAppMeasurement.git", - "state" : { - "revision" : "56f681586ff006a7982b53dc94082eea31971acf", - "version" : "10.16.0" - } - }, - { - "identity" : "googledatatransport", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleDataTransport.git", - "state" : { - "revision" : "aae45a320fd0d11811820335b1eabc8753902a40", - "version" : "9.2.5" - } - }, - { - "identity" : "googlesignin-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleSignIn-iOS", - "state" : { - "revision" : "7932d33686c1dc4d7df7a919aae47361d1cdfda4", - "version" : "7.0.0" - } - }, - { - "identity" : "googleutilities", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleUtilities.git", - "state" : { - "revision" : "c38ce365d77b04a9a300c31061c5227589e5597b", - "version" : "7.11.5" - } - }, - { - "identity" : "grpc-binary", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/grpc-binary.git", - "state" : { - "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", - "version" : "1.49.1" - } - }, - { - "identity" : "gtm-session-fetcher", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/gtm-session-fetcher.git", - "state" : { - "revision" : "d415594121c9e8a4f9d79cecee0965cf35e74dbd", - "version" : "3.1.1" - } - }, - { - "identity" : "gtmappauth", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GTMAppAuth.git", - "state" : { - "revision" : "cee3c709307912d040bd1e06ca919875a92339c6", - "version" : "2.0.0" - } - }, - { - "identity" : "interop-ios-for-google-sdks", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/interop-ios-for-google-sdks.git", - "state" : { - "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", - "version" : "100.0.0" - } - }, - { - "identity" : "leveldb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/leveldb.git", - "state" : { - "revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", - "version" : "1.22.2" - } - }, - { - "identity" : "nanopb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/nanopb.git", - "state" : { - "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", - "version" : "2.30909.0" - } - }, - { - "identity" : "promises", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/promises.git", - "state" : { - "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", - "version" : "2.3.1" - } - }, - { - "identity" : "swift-protobuf", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-protobuf.git", - "state" : { - "revision" : "3c54ab05249f59f2c6641dd2920b8358ea9ed127", - "version" : "1.24.0" - } - } - ], - "version" : 2 -} diff --git a/Helfy.xcodeproj/xcshareddata/xcschemes/Helfy.xcscheme b/Helfy.xcodeproj/xcshareddata/xcschemes/Helfy.xcscheme index 6a66380..99eb207 100644 --- a/Helfy.xcodeproj/xcshareddata/xcschemes/Helfy.xcscheme +++ b/Helfy.xcodeproj/xcshareddata/xcschemes/Helfy.xcscheme @@ -49,6 +49,13 @@ ReferencedContainer = "container:Helfy.xcodeproj"> + + + + ()) { + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/quiz/users") else { + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let quizHomeParsedData = try JSONDecoder().decode(QuizHomeModel.self, from: data) + completion(quizHomeParsedData) + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } + + func getQuizData(type: String, completion: @escaping (Quiz) -> ()) { + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/quiz?type=\(type)") else { return } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let quizParsedData = try JSONDecoder().decode(Quiz.self, from: data) + completion(quizParsedData) + + print("quizParsedData: \(quizParsedData)") + print("❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥❤️‍🔥") + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } +} diff --git a/Helfy/APIHandler/CategoryAPIHandler.swift b/Helfy/APIHandler/CategoryAPIHandler.swift new file mode 100644 index 0000000..c633f03 --- /dev/null +++ b/Helfy/APIHandler/CategoryAPIHandler.swift @@ -0,0 +1,47 @@ +// +// File.swift +// Helfy +// +// Created by 윤성은 on 2/18/24. +// + +import Foundation + +class CategoryAPIHandler { + + let token = UserDefaults.standard.string(forKey: "GoogleToken") ?? "" + + func getCategoryData(completion: @escaping (CategoryModel) -> ()) { + print("getCategoryData called") + + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/categories") else { + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let categoryParsedData = try JSONDecoder().decode(CategoryModel.self, from: data) + completion(categoryParsedData) + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } +} diff --git a/Helfy/APIHandler/CategoryPageAPIHandler.swift b/Helfy/APIHandler/CategoryPageAPIHandler.swift new file mode 100644 index 0000000..26fe460 --- /dev/null +++ b/Helfy/APIHandler/CategoryPageAPIHandler.swift @@ -0,0 +1,42 @@ +// +// CategoryPageAPIHandler.swift +// Helfy +// +// Created by YEOMI on 2/12/24. +// + +import Foundation + +class APIHandler { + func getCategoryPageData(category: String,completion: @escaping (CategoryPageModel) -> ()) { + //let key = "발급받은 API키" + + // 1. 사전준비 단계에서 발급받은 key를 활용하여 requestURL 생성 + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/information?category=\(category)") else { + print("유효하지 않은 url입니다.") + return + } + var requestURL = URLRequest(url: url) + requestURL.httpMethod = "GET" + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출 + guard error == nil else { + print(error?.localizedDescription) + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + //가공 + let parsedData = try JSONDecoder().decode(CategoryPageModel.self, from: data) + completion(parsedData) + } catch { + print("Error decoding data: \(error.localizedDescription)") + } + + } + }.resume() + } +} diff --git a/Helfy/APIHandler/ImageLoader.swift b/Helfy/APIHandler/ImageLoader.swift new file mode 100644 index 0000000..d715114 --- /dev/null +++ b/Helfy/APIHandler/ImageLoader.swift @@ -0,0 +1,55 @@ +// +// ImageLoader.swift +// Helfy +// +// Created by YEOMI on 2/12/24. +// + +import Foundation +import UIKit + +class ImageLoader { + private static let imageCache = NSCache() + + static func loadImage(url: String, completion: @escaping (UIImage?) -> Void) { + // url이 비어있다면 nil처리 + if url.isEmpty { + completion(nil) + return + } + + // URL 형식으로 변환 + let realURL = URL(string: url)! + + // 캐시에 있다면 바로 반환 + if let image = imageCache.object(forKey: realURL.lastPathComponent as NSString) { + print("캐시에 존재 😎") + // UI는 메인 쓰레드에서 진행 + DispatchQueue.main.async { + completion(image) + } + return + } + + // 캐시에 없다면 + DispatchQueue.global(qos: .background).async { + print("캐시에 없음 🥲") + // 데이터 타입 변환 + if let data = try? Data(contentsOf: realURL) { + // 이미지 변환 + let image = UIImage(data: data)! + // cache에 추가 + self.imageCache.setObject(image, forKey: realURL.lastPathComponent as NSString) + // UI는 메인 쓰레드에서 진행 + DispatchQueue.main.async { + completion(image) + } + } else { + DispatchQueue.main.async { + completion(nil) + } + } + } + + } +} diff --git a/Helfy/APIHandler/MainAPIHandler.swift b/Helfy/APIHandler/MainAPIHandler.swift new file mode 100644 index 0000000..cb33d61 --- /dev/null +++ b/Helfy/APIHandler/MainAPIHandler.swift @@ -0,0 +1,45 @@ +// +// MainAPIHandler.swift +// Helfy +// +// Created by 윤성은 on 2/5/24. +// + +import Foundation + +class MainAPIHandler { + + let token = UserDefaults.standard.string(forKey: "GoogleToken") ?? "" + + func getMainData(completion: @escaping (MainModel) -> ()) { + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/weather") else { + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let mainParsedData = try JSONDecoder().decode(MainModel.self, from: data) + completion(mainParsedData) + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } +} diff --git a/Helfy/Assets.xcassets/Cold wave.imageset/Contents.json b/Helfy/Assets.xcassets/Cold wave.imageset/Contents.json new file mode 100644 index 0000000..e59e441 --- /dev/null +++ b/Helfy/Assets.xcassets/Cold wave.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "한파 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "한파@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "한파@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214 1.png" "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214 1.png" new file mode 100644 index 0000000..8132735 Binary files /dev/null and "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214 1.png" differ diff --git "a/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@2x.png" "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@2x.png" new file mode 100644 index 0000000..a3a0f8a Binary files /dev/null and "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@2x.png" differ diff --git "a/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@3x.png" "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@3x.png" new file mode 100644 index 0000000..dc5f61c Binary files /dev/null and "b/Helfy/Assets.xcassets/Cold wave.imageset/\355\225\234\355\214\214@3x.png" differ diff --git "a/Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/Contents.json" b/Helfy/Assets.xcassets/Drought.imageset/Contents.json similarity index 71% rename from "Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/Contents.json" rename to Helfy/Assets.xcassets/Drought.imageset/Contents.json index 442a089..bd18581 100644 --- "a/Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/Contents.json" +++ b/Helfy/Assets.xcassets/Drought.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "가뭄.png", + "filename" : "Drought 1.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Drought@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Drought@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Helfy/Assets.xcassets/Drought.imageset/Drought 1.png b/Helfy/Assets.xcassets/Drought.imageset/Drought 1.png new file mode 100644 index 0000000..b57fae7 Binary files /dev/null and b/Helfy/Assets.xcassets/Drought.imageset/Drought 1.png differ diff --git a/Helfy/Assets.xcassets/Drought.imageset/Drought@2x.png b/Helfy/Assets.xcassets/Drought.imageset/Drought@2x.png new file mode 100644 index 0000000..6f1f96e Binary files /dev/null and b/Helfy/Assets.xcassets/Drought.imageset/Drought@2x.png differ diff --git a/Helfy/Assets.xcassets/Drought.imageset/Drought@3x.png b/Helfy/Assets.xcassets/Drought.imageset/Drought@3x.png new file mode 100644 index 0000000..274c77b Binary files /dev/null and b/Helfy/Assets.xcassets/Drought.imageset/Drought@3x.png differ diff --git a/Helfy/Assets.xcassets/Dust storm.imageset/Contents.json b/Helfy/Assets.xcassets/Dust storm.imageset/Contents.json new file mode 100644 index 0000000..ec1a87c --- /dev/null +++ b/Helfy/Assets.xcassets/Dust storm.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Dust storm 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Dust storm@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Dust storm@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm 1.png b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm 1.png new file mode 100644 index 0000000..e49bc30 Binary files /dev/null and b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm 1.png differ diff --git a/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@2x.png b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@2x.png new file mode 100644 index 0000000..7d04998 Binary files /dev/null and b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@2x.png differ diff --git a/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@3x.png b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@3x.png new file mode 100644 index 0000000..9918719 Binary files /dev/null and b/Helfy/Assets.xcassets/Dust storm.imageset/Dust storm@3x.png differ diff --git a/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Contents.json b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Contents.json new file mode 100644 index 0000000..bc4f4fe --- /dev/null +++ b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Earthquake and tsunami 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Earthquake and tsunami@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Earthquake and tsunami@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami 1.png b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami 1.png new file mode 100644 index 0000000..ab5d4c3 Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami 1.png differ diff --git a/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@2x.png b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@2x.png new file mode 100644 index 0000000..fbae297 Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@2x.png differ diff --git a/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@3x.png b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@3x.png new file mode 100644 index 0000000..fb6d537 Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake and tsunami.imageset/Earthquake and tsunami@3x.png differ diff --git a/Helfy/Assets.xcassets/Earthquake.imageset/Contents.json b/Helfy/Assets.xcassets/Earthquake.imageset/Contents.json new file mode 100644 index 0000000..923dfd8 --- /dev/null +++ b/Helfy/Assets.xcassets/Earthquake.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Earthquake 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Earthquake@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Earthquake@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake 1.png b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake 1.png new file mode 100644 index 0000000..75c04e2 Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake 1.png differ diff --git a/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@2x.png b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@2x.png new file mode 100644 index 0000000..aa6b61d Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@2x.png differ diff --git a/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@3x.png b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@3x.png new file mode 100644 index 0000000..2730612 Binary files /dev/null and b/Helfy/Assets.xcassets/Earthquake.imageset/Earthquake@3x.png differ diff --git "a/Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/Contents.json" b/Helfy/Assets.xcassets/Flood.imageset/Contents.json similarity index 71% rename from "Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/Contents.json" rename to Helfy/Assets.xcassets/Flood.imageset/Contents.json index 3baeed6..a1fb974 100644 --- "a/Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/Contents.json" +++ b/Helfy/Assets.xcassets/Flood.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "free-icon-lightning-7105134.png", + "filename" : "홍수 1.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "홍수@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "홍수@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git "a/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230 1.png" "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230 1.png" new file mode 100644 index 0000000..082cd3e Binary files /dev/null and "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230 1.png" differ diff --git "a/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@2x.png" "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@2x.png" new file mode 100644 index 0000000..2dbc79c Binary files /dev/null and "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@2x.png" differ diff --git "a/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@3x.png" "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@3x.png" new file mode 100644 index 0000000..53d844e Binary files /dev/null and "b/Helfy/Assets.xcassets/Flood.imageset/\355\231\215\354\210\230@3x.png" differ diff --git a/Helfy/Assets.xcassets/Green tide.imageset/Contents.json b/Helfy/Assets.xcassets/Green tide.imageset/Contents.json new file mode 100644 index 0000000..7d2ab2f --- /dev/null +++ b/Helfy/Assets.xcassets/Green tide.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Green tide 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Green tide@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Green tide@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Green tide.imageset/Green tide 1.png b/Helfy/Assets.xcassets/Green tide.imageset/Green tide 1.png new file mode 100644 index 0000000..4fd4eea Binary files /dev/null and b/Helfy/Assets.xcassets/Green tide.imageset/Green tide 1.png differ diff --git a/Helfy/Assets.xcassets/Green tide.imageset/Green tide@2x.png b/Helfy/Assets.xcassets/Green tide.imageset/Green tide@2x.png new file mode 100644 index 0000000..710f44f Binary files /dev/null and b/Helfy/Assets.xcassets/Green tide.imageset/Green tide@2x.png differ diff --git a/Helfy/Assets.xcassets/Green tide.imageset/Green tide@3x.png b/Helfy/Assets.xcassets/Green tide.imageset/Green tide@3x.png new file mode 100644 index 0000000..fd711ac Binary files /dev/null and b/Helfy/Assets.xcassets/Green tide.imageset/Green tide@3x.png differ diff --git a/Helfy/Assets.xcassets/Heat wave.imageset/Contents.json b/Helfy/Assets.xcassets/Heat wave.imageset/Contents.json new file mode 100644 index 0000000..9c2bb3b --- /dev/null +++ b/Helfy/Assets.xcassets/Heat wave.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Heat wave 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Heat wave@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Heat wave@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave 1.png b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave 1.png new file mode 100644 index 0000000..76affd2 Binary files /dev/null and b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave 1.png differ diff --git a/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@2x.png b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@2x.png new file mode 100644 index 0000000..cbb56ac Binary files /dev/null and b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@2x.png differ diff --git a/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@3x.png b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@3x.png new file mode 100644 index 0000000..f4e1933 Binary files /dev/null and b/Helfy/Assets.xcassets/Heat wave.imageset/Heat wave@3x.png differ diff --git a/Helfy/Assets.xcassets/Heavy rain.imageset/Contents.json b/Helfy/Assets.xcassets/Heavy rain.imageset/Contents.json new file mode 100644 index 0000000..13d7967 --- /dev/null +++ b/Helfy/Assets.xcassets/Heavy rain.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Heavy rain 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Heavy rain@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Heavy rain@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain 1.png b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain 1.png new file mode 100644 index 0000000..2421ec5 Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain 1.png differ diff --git a/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@2x.png b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@2x.png new file mode 100644 index 0000000..7222c3c Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@2x.png differ diff --git a/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@3x.png b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@3x.png new file mode 100644 index 0000000..4470c4c Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy rain.imageset/Heavy rain@3x.png differ diff --git a/Helfy/Assets.xcassets/Heavy snow.imageset/Contents.json b/Helfy/Assets.xcassets/Heavy snow.imageset/Contents.json new file mode 100644 index 0000000..72a39d3 --- /dev/null +++ b/Helfy/Assets.xcassets/Heavy snow.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Heavy snow 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Heavy snow@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Heavy snow@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow 1.png b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow 1.png new file mode 100644 index 0000000..879c0c1 Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow 1.png differ diff --git a/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@2x.png b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@2x.png new file mode 100644 index 0000000..261a807 Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@2x.png differ diff --git a/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@3x.png b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@3x.png new file mode 100644 index 0000000..6de70ca Binary files /dev/null and b/Helfy/Assets.xcassets/Heavy snow.imageset/Heavy snow@3x.png differ diff --git a/Helfy/Assets.xcassets/Landslide.imageset/Contents.json b/Helfy/Assets.xcassets/Landslide.imageset/Contents.json new file mode 100644 index 0000000..7e189db --- /dev/null +++ b/Helfy/Assets.xcassets/Landslide.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Landslide 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Landslide@2x 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Landslide@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Landslide.imageset/Landslide 1.png b/Helfy/Assets.xcassets/Landslide.imageset/Landslide 1.png new file mode 100644 index 0000000..e90abb5 Binary files /dev/null and b/Helfy/Assets.xcassets/Landslide.imageset/Landslide 1.png differ diff --git a/Helfy/Assets.xcassets/Landslide.imageset/Landslide@2x 1.png b/Helfy/Assets.xcassets/Landslide.imageset/Landslide@2x 1.png new file mode 100644 index 0000000..756f7f6 Binary files /dev/null and b/Helfy/Assets.xcassets/Landslide.imageset/Landslide@2x 1.png differ diff --git a/Helfy/Assets.xcassets/Landslide.imageset/Landslide@3x.png b/Helfy/Assets.xcassets/Landslide.imageset/Landslide@3x.png new file mode 100644 index 0000000..b09d859 Binary files /dev/null and b/Helfy/Assets.xcassets/Landslide.imageset/Landslide@3x.png differ diff --git a/Helfy/Assets.xcassets/Lightning.imageset/Contents.json b/Helfy/Assets.xcassets/Lightning.imageset/Contents.json new file mode 100644 index 0000000..d2bcae8 --- /dev/null +++ b/Helfy/Assets.xcassets/Lightning.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Lightning 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Lightning@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Lightning@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Lightning.imageset/Lightning 1.png b/Helfy/Assets.xcassets/Lightning.imageset/Lightning 1.png new file mode 100644 index 0000000..4924719 Binary files /dev/null and b/Helfy/Assets.xcassets/Lightning.imageset/Lightning 1.png differ diff --git a/Helfy/Assets.xcassets/Lightning.imageset/Lightning@2x.png b/Helfy/Assets.xcassets/Lightning.imageset/Lightning@2x.png new file mode 100644 index 0000000..142a254 Binary files /dev/null and b/Helfy/Assets.xcassets/Lightning.imageset/Lightning@2x.png differ diff --git a/Helfy/Assets.xcassets/Lightning.imageset/Lightning@3x.png b/Helfy/Assets.xcassets/Lightning.imageset/Lightning@3x.png new file mode 100644 index 0000000..5c05451 Binary files /dev/null and b/Helfy/Assets.xcassets/Lightning.imageset/Lightning@3x.png differ diff --git a/Helfy/Assets.xcassets/Natural space object crash.imageset/Contents.json b/Helfy/Assets.xcassets/Natural space object crash.imageset/Contents.json new file mode 100644 index 0000000..9cf9e68 --- /dev/null +++ b/Helfy/Assets.xcassets/Natural space object crash.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Natural space object crash 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Natural space object crash@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Natural space object crash@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash 1.png b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash 1.png new file mode 100644 index 0000000..bc61378 Binary files /dev/null and b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash 1.png differ diff --git a/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@2x.png b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@2x.png new file mode 100644 index 0000000..a70c25c Binary files /dev/null and b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@2x.png differ diff --git a/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@3x.png b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@3x.png new file mode 100644 index 0000000..f3d0e81 Binary files /dev/null and b/Helfy/Assets.xcassets/Natural space object crash.imageset/Natural space object crash@3x.png differ diff --git a/Helfy/Assets.xcassets/Red tide.imageset/Contents.json b/Helfy/Assets.xcassets/Red tide.imageset/Contents.json new file mode 100644 index 0000000..47101dc --- /dev/null +++ b/Helfy/Assets.xcassets/Red tide.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Red tide 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Red tide@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Red tide@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Red tide.imageset/Red tide 1.png b/Helfy/Assets.xcassets/Red tide.imageset/Red tide 1.png new file mode 100644 index 0000000..08c9a36 Binary files /dev/null and b/Helfy/Assets.xcassets/Red tide.imageset/Red tide 1.png differ diff --git a/Helfy/Assets.xcassets/Red tide.imageset/Red tide@2x.png b/Helfy/Assets.xcassets/Red tide.imageset/Red tide@2x.png new file mode 100644 index 0000000..1800a5c Binary files /dev/null and b/Helfy/Assets.xcassets/Red tide.imageset/Red tide@2x.png differ diff --git a/Helfy/Assets.xcassets/Red tide.imageset/Red tide@3x.png b/Helfy/Assets.xcassets/Red tide.imageset/Red tide@3x.png new file mode 100644 index 0000000..99e9d0a Binary files /dev/null and b/Helfy/Assets.xcassets/Red tide.imageset/Red tide@3x.png differ diff --git a/Helfy/Assets.xcassets/Rough sea.imageset/Contents.json b/Helfy/Assets.xcassets/Rough sea.imageset/Contents.json new file mode 100644 index 0000000..69d123b --- /dev/null +++ b/Helfy/Assets.xcassets/Rough sea.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Rough sea 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Rough sea@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Rough sea@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea 1.png b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea 1.png new file mode 100644 index 0000000..a28f6af Binary files /dev/null and b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea 1.png differ diff --git a/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@2x.png b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@2x.png new file mode 100644 index 0000000..6dcd948 Binary files /dev/null and b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@2x.png differ diff --git a/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@3x.png b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@3x.png new file mode 100644 index 0000000..abc21c6 Binary files /dev/null and b/Helfy/Assets.xcassets/Rough sea.imageset/Rough sea@3x.png differ diff --git a/Helfy/Assets.xcassets/Sea level rise.imageset/Contents.json b/Helfy/Assets.xcassets/Sea level rise.imageset/Contents.json new file mode 100644 index 0000000..ebc2e21 --- /dev/null +++ b/Helfy/Assets.xcassets/Sea level rise.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Sea level rise 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Sea level rise@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Sea level rise@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise 1.png b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise 1.png new file mode 100644 index 0000000..e4138e1 Binary files /dev/null and b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise 1.png differ diff --git a/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@2x.png b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@2x.png new file mode 100644 index 0000000..8a5124f Binary files /dev/null and b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@2x.png differ diff --git a/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@3x.png b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@3x.png new file mode 100644 index 0000000..7201ee4 Binary files /dev/null and b/Helfy/Assets.xcassets/Sea level rise.imageset/Sea level rise@3x.png differ diff --git a/Helfy/Assets.xcassets/Space radio disaster.imageset/Contents.json b/Helfy/Assets.xcassets/Space radio disaster.imageset/Contents.json new file mode 100644 index 0000000..29c821b --- /dev/null +++ b/Helfy/Assets.xcassets/Space radio disaster.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Space radio disaster 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Space radio disaster@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Space radio disaster@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster 1.png b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster 1.png new file mode 100644 index 0000000..5730a8b Binary files /dev/null and b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster 1.png differ diff --git a/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@2x.png b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@2x.png new file mode 100644 index 0000000..f3c3427 Binary files /dev/null and b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@2x.png differ diff --git a/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@3x.png b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@3x.png new file mode 100644 index 0000000..429f6dc Binary files /dev/null and b/Helfy/Assets.xcassets/Space radio disaster.imageset/Space radio disaster@3x.png differ diff --git a/Helfy/Assets.xcassets/Strong wind.imageset/Contents.json b/Helfy/Assets.xcassets/Strong wind.imageset/Contents.json new file mode 100644 index 0000000..d36bfac --- /dev/null +++ b/Helfy/Assets.xcassets/Strong wind.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Strong wind 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Strong wind@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Strong wind@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind 1.png b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind 1.png new file mode 100644 index 0000000..dad58f7 Binary files /dev/null and b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind 1.png differ diff --git a/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@2x.png b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@2x.png new file mode 100644 index 0000000..7afb50a Binary files /dev/null and b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@2x.png differ diff --git a/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@3x.png b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@3x.png new file mode 100644 index 0000000..64729e4 Binary files /dev/null and b/Helfy/Assets.xcassets/Strong wind.imageset/Strong wind@3x.png differ diff --git "a/Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/Contents.json" b/Helfy/Assets.xcassets/Tsunami.imageset/Contents.json similarity index 71% rename from "Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/Contents.json" rename to Helfy/Assets.xcassets/Tsunami.imageset/Contents.json index 61b6fb9..6b5e93d 100644 --- "a/Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/Contents.json" +++ b/Helfy/Assets.xcassets/Tsunami.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "녹조.png", + "filename" : "Tsunami 1.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Tsunami@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Tsunami@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami 1.png b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami 1.png new file mode 100644 index 0000000..1e10665 Binary files /dev/null and b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami 1.png differ diff --git a/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@2x.png b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@2x.png new file mode 100644 index 0000000..616921e Binary files /dev/null and b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@2x.png differ diff --git a/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@3x.png b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@3x.png new file mode 100644 index 0000000..6adda43 Binary files /dev/null and b/Helfy/Assets.xcassets/Tsunami.imageset/Tsunami@3x.png differ diff --git "a/Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/Contents.json" b/Helfy/Assets.xcassets/Typhoon.imageset/Contents.json similarity index 71% rename from "Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/Contents.json" rename to Helfy/Assets.xcassets/Typhoon.imageset/Contents.json index 27d80eb..83280ef 100644 --- "a/Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/Contents.json" +++ b/Helfy/Assets.xcassets/Typhoon.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "강풍.png", + "filename" : "Typhoon 1.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Typhoon@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Typhoon@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon 1.png b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon 1.png new file mode 100644 index 0000000..ff45943 Binary files /dev/null and b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon 1.png differ diff --git a/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@2x.png b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@2x.png new file mode 100644 index 0000000..4bd8ea1 Binary files /dev/null and b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@2x.png differ diff --git a/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@3x.png b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@3x.png new file mode 100644 index 0000000..7fa8f68 Binary files /dev/null and b/Helfy/Assets.xcassets/Typhoon.imageset/Typhoon@3x.png differ diff --git a/Helfy/Assets.xcassets/Volcanic eruption.imageset/Contents.json b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Contents.json new file mode 100644 index 0000000..bc48c1c --- /dev/null +++ b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Volcanic eruption 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Volcanic eruption@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Volcanic eruption@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption 1.png b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption 1.png new file mode 100644 index 0000000..5079541 Binary files /dev/null and b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption 1.png differ diff --git a/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@2x.png b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@2x.png new file mode 100644 index 0000000..691bddd Binary files /dev/null and b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@2x.png differ diff --git a/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@3x.png b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@3x.png new file mode 100644 index 0000000..7bc7c98 Binary files /dev/null and b/Helfy/Assets.xcassets/Volcanic eruption.imageset/Volcanic eruption@3x.png differ diff --git a/Helfy/Assets.xcassets/flooding.imageset/Contents.json b/Helfy/Assets.xcassets/flooding.imageset/Contents.json new file mode 100644 index 0000000..30a2137 --- /dev/null +++ b/Helfy/Assets.xcassets/flooding.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Flooding 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Flooding@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Flooding@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Helfy/Assets.xcassets/flooding.imageset/Flooding 1.png b/Helfy/Assets.xcassets/flooding.imageset/Flooding 1.png new file mode 100644 index 0000000..35fb039 Binary files /dev/null and b/Helfy/Assets.xcassets/flooding.imageset/Flooding 1.png differ diff --git a/Helfy/Assets.xcassets/flooding.imageset/Flooding@2x.png b/Helfy/Assets.xcassets/flooding.imageset/Flooding@2x.png new file mode 100644 index 0000000..e82b961 Binary files /dev/null and b/Helfy/Assets.xcassets/flooding.imageset/Flooding@2x.png differ diff --git a/Helfy/Assets.xcassets/flooding.imageset/Flooding@3x.png b/Helfy/Assets.xcassets/flooding.imageset/Flooding@3x.png new file mode 100644 index 0000000..34191c7 Binary files /dev/null and b/Helfy/Assets.xcassets/flooding.imageset/Flooding@3x.png differ diff --git "a/Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/\352\260\200\353\255\204.png" "b/Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/\352\260\200\353\255\204.png" deleted file mode 100644 index c736dfe..0000000 Binary files "a/Helfy/Assets.xcassets/\352\260\200\353\255\204.imageset/\352\260\200\353\255\204.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/\352\260\225\355\222\215.png" "b/Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/\352\260\225\355\222\215.png" deleted file mode 100644 index c9f2d91..0000000 Binary files "a/Helfy/Assets.xcassets/\352\260\225\355\222\215.imageset/\352\260\225\355\222\215.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/free-icon-lightning-7105134.png" "b/Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/free-icon-lightning-7105134.png" deleted file mode 100644 index 9b54c38..0000000 Binary files "a/Helfy/Assets.xcassets/\353\202\231\353\242\260.imageset/free-icon-lightning-7105134.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/\353\205\271\354\241\260.png" "b/Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/\353\205\271\354\241\260.png" deleted file mode 100644 index f961889..0000000 Binary files "a/Helfy/Assets.xcassets/\353\205\271\354\241\260.imageset/\353\205\271\354\241\260.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/Contents.json" "b/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/Contents.json" deleted file mode 100644 index ad3bcaf..0000000 --- "a/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "대설.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/\353\214\200\354\204\244.png" "b/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/\353\214\200\354\204\244.png" deleted file mode 100644 index 4f3ea3f..0000000 Binary files "a/Helfy/Assets.xcassets/\353\214\200\354\204\244.imageset/\353\214\200\354\204\244.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/Contents.json" deleted file mode 100644 index 70950e4..0000000 --- "a/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "산사태.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/\354\202\260\354\202\254\355\203\234.png" "b/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/\354\202\260\354\202\254\355\203\234.png" deleted file mode 100644 index 676c0cf..0000000 Binary files "a/Helfy/Assets.xcassets/\354\202\260\354\202\254\355\203\234.imageset/\354\202\260\354\202\254\355\203\234.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/Contents.json" deleted file mode 100644 index fea079a..0000000 --- "a/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "우주전파재난.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.png" "b/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.png" deleted file mode 100644 index 765c853..0000000 Binary files "a/Helfy/Assets.xcassets/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.imageset/\354\232\260\354\243\274\354\240\204\355\214\214\354\236\254\353\202\234.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/Contents.json" deleted file mode 100644 index d453363..0000000 --- "a/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "자연우주물체추락.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.png" "b/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.png" deleted file mode 100644 index aae8018..0000000 Binary files "a/Helfy/Assets.xcassets/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.imageset/\354\236\220\354\227\260\354\232\260\354\243\274\353\254\274\354\262\264\354\266\224\353\235\275.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/Contents.json" deleted file mode 100644 index 459cb0d..0000000 --- "a/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "적조.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/\354\240\201\354\241\260.png" "b/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/\354\240\201\354\241\260.png" deleted file mode 100644 index 300f10c..0000000 Binary files "a/Helfy/Assets.xcassets/\354\240\201\354\241\260.imageset/\354\240\201\354\241\260.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/Contents.json" deleted file mode 100644 index 9e4dacd..0000000 --- "a/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "지진.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/\354\247\200\354\247\204.png" "b/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/\354\247\200\354\247\204.png" deleted file mode 100644 index b5f168f..0000000 Binary files "a/Helfy/Assets.xcassets/\354\247\200\354\247\204.imageset/\354\247\200\354\247\204.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/Contents.json" deleted file mode 100644 index ee233a4..0000000 --- "a/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "지진해일.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/\354\247\200\354\247\204\355\225\264\354\235\274.png" "b/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/\354\247\200\354\247\204\355\225\264\354\235\274.png" deleted file mode 100644 index 84a4f28..0000000 Binary files "a/Helfy/Assets.xcassets/\354\247\200\354\247\204\355\225\264\354\235\274.imageset/\354\247\200\354\247\204\355\225\264\354\235\274.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/Contents.json" "b/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/Contents.json" deleted file mode 100644 index 5735b44..0000000 --- "a/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "침수.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/\354\271\250\354\210\230.png" "b/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/\354\271\250\354\210\230.png" deleted file mode 100644 index 6710ce5..0000000 Binary files "a/Helfy/Assets.xcassets/\354\271\250\354\210\230.imageset/\354\271\250\354\210\230.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/Contents.json" deleted file mode 100644 index 715a82c..0000000 --- "a/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "태풍.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/\355\203\234\355\222\215.png" "b/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/\355\203\234\355\222\215.png" deleted file mode 100644 index dac5036..0000000 Binary files "a/Helfy/Assets.xcassets/\355\203\234\355\222\215.imageset/\355\203\234\355\222\215.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/Contents.json" deleted file mode 100644 index b0655c0..0000000 --- "a/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "폭염.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/\355\217\255\354\227\274.png" "b/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/\355\217\255\354\227\274.png" deleted file mode 100644 index 38a78ee..0000000 Binary files "a/Helfy/Assets.xcassets/\355\217\255\354\227\274.imageset/\355\217\255\354\227\274.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/Contents.json" deleted file mode 100644 index 59968f5..0000000 --- "a/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "풍랑.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/\355\222\215\353\236\221.png" "b/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/\355\222\215\353\236\221.png" deleted file mode 100644 index b2030f7..0000000 Binary files "a/Helfy/Assets.xcassets/\355\222\215\353\236\221.imageset/\355\222\215\353\236\221.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/Contents.json" deleted file mode 100644 index 6b7172e..0000000 --- "a/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "한파.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/\355\225\234\355\214\214.png" "b/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/\355\225\234\355\214\214.png" deleted file mode 100644 index a8ad8b5..0000000 Binary files "a/Helfy/Assets.xcassets/\355\225\234\355\214\214.imageset/\355\225\234\355\214\214.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/Contents.json" deleted file mode 100644 index 83c7d5b..0000000 --- "a/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "해수면상승.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.png" "b/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.png" deleted file mode 100644 index 0ddcfa1..0000000 Binary files "a/Helfy/Assets.xcassets/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.imageset/\355\225\264\354\210\230\353\251\264\354\203\201\354\212\271.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/Contents.json" deleted file mode 100644 index 1378fa6..0000000 --- "a/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "해일.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/\355\225\264\354\235\274.png" "b/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/\355\225\264\354\235\274.png" deleted file mode 100644 index 79c4e38..0000000 Binary files "a/Helfy/Assets.xcassets/\355\225\264\354\235\274.imageset/\355\225\264\354\235\274.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/Contents.json" deleted file mode 100644 index df49c1e..0000000 --- "a/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "호우.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/\355\230\270\354\232\260.png" "b/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/\355\230\270\354\232\260.png" deleted file mode 100644 index 2c56299..0000000 Binary files "a/Helfy/Assets.xcassets/\355\230\270\354\232\260.imageset/\355\230\270\354\232\260.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/Contents.json" deleted file mode 100644 index d39b1cb..0000000 --- "a/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "홍수.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/\355\231\215\354\210\230.png" "b/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/\355\231\215\354\210\230.png" deleted file mode 100644 index d6f982c..0000000 Binary files "a/Helfy/Assets.xcassets/\355\231\215\354\210\230.imageset/\355\231\215\354\210\230.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/Contents.json" deleted file mode 100644 index d1b2f79..0000000 --- "a/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "화산폭발.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/\355\231\224\354\202\260\355\217\255\353\260\234.png" "b/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/\355\231\224\354\202\260\355\217\255\353\260\234.png" deleted file mode 100644 index d910c95..0000000 Binary files "a/Helfy/Assets.xcassets/\355\231\224\354\202\260\355\217\255\353\260\234.imageset/\355\231\224\354\202\260\355\217\255\353\260\234.png" and /dev/null differ diff --git "a/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/Contents.json" "b/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/Contents.json" deleted file mode 100644 index 091461e..0000000 --- "a/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/Contents.json" +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "황사.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git "a/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/\355\231\251\354\202\254.png" "b/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/\355\231\251\354\202\254.png" deleted file mode 100644 index 5bc3d99..0000000 Binary files "a/Helfy/Assets.xcassets/\355\231\251\354\202\254.imageset/\355\231\251\354\202\254.png" and /dev/null differ diff --git a/Helfy/Controller/BannerViewController.swift b/Helfy/Controller/BannerViewController.swift new file mode 100644 index 0000000..fbfcd0e --- /dev/null +++ b/Helfy/Controller/BannerViewController.swift @@ -0,0 +1,39 @@ +// +// BannerViewController.swift +// Helfy +// +// Created by YEOMI on 2/10/24. +// +import UIKit + +class BannerViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let bannerWidth: CGFloat = view.bounds.width * 0.9 + let bannerHeight: CGFloat = view.bounds.height * 0.7 + let bannerX: CGFloat = (view.bounds.width - bannerWidth) / 2 + let bannerY: CGFloat = (view.bounds.height - bannerHeight) / 2 + let bannerFrame = CGRect(x: bannerX, y: bannerY, width: bannerWidth, height: bannerHeight) + + let banner = BannerView(frame: bannerFrame) + banner.translatesAutoresizingMaskIntoConstraints = false + banner.banners = [ + (image: UIImage(named: "bg2")!, text: "재난시 대피요령"), + (image: UIImage(named: "img3")!, text: "재난시 대피요령 2"), + (image: UIImage(named: "img3")!, text: "재난시 대피요령 3") + ] + view.addSubview(banner) + + view.backgroundColor = .white // 여기를 추가합니다. + let screenHeight = UIScreen.main.bounds.height + NSLayoutConstraint.activate([ + banner.topAnchor.constraint(equalTo: view.topAnchor, constant: screenHeight * 0.3), + banner.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20), + banner.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20), + banner.heightAnchor.constraint(equalToConstant: 500) + ]) + } + + +} diff --git a/Helfy/Controller/CategoryPageViewController.swift b/Helfy/Controller/CategoryPageViewController.swift new file mode 100644 index 0000000..c6f7c13 --- /dev/null +++ b/Helfy/Controller/CategoryPageViewController.swift @@ -0,0 +1,60 @@ +// +// CategoryPageViewController.swift +// Helfy +// +// Created by YEOMI on 11/29/23. +// +import UIKit + +class CategoryPageViewController: UIViewController { + + let categoryPageViewInstance = CategoryPageView() + + lazy var newsURL = categoryPageViewInstance.newsURL + lazy var youtubeURL = categoryPageViewInstance.youtubeURL + + private var categoryPageView: CategoryPageView! + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + private func setupUI() { + view.backgroundColor = .white + + categoryPageView = CategoryPageView() + categoryPageView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(categoryPageView) + + NSLayoutConstraint.activate([ + categoryPageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + categoryPageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + categoryPageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + categoryPageView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + + categoryPageView.setNewsButtonTarget(self, action: #selector(newsButtonTapped)) + categoryPageView.setYouTubeButtonTarget(self, action: #selector(youtubeButtonTapped)) + } + + + + + @objc func newsButtonTapped() { + // Handle news button tap + print("News URL:", newsURL) //디버깅 용도 + if let url = URL(string: newsURL) { + UIApplication.shared.open(url) + } + } + + @objc func youtubeButtonTapped() { + // Handle YouTube button tap + print("YouTube URL:", youtubeURL) //디버깅 용도 + if let url = URL(string: youtubeURL) { + UIApplication.shared.open(url) + } + } +} + diff --git a/Helfy/Controller/CategoryViewController.swift b/Helfy/Controller/CategoryViewController.swift new file mode 100644 index 0000000..6a87d5b --- /dev/null +++ b/Helfy/Controller/CategoryViewController.swift @@ -0,0 +1,210 @@ +// +// CategoryViewController.swift +// Helfy +// +// Created by 윤성은 on 11/30/23. +// + +import UIKit + +class CategoryViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + var categoryView: CategoryView? + let categoryApiHandler = CategoryAPIHandler() + let categoryPageViewController = CategoryPageViewController() + +// let categoryPageApiHandler = CategoryPageAPIHandler() + var categoryModelData: CategoryModel? { + didSet { + print("hi") + } + } + var categoryData: CategoryModel? + + var buttonLabels = ["가뭄", "강풍", "낙뢰", "녹조", "대설", "산사태", "적조", "지진", "지진해일", "침수", "태풍", "폭염", "풍랑", "한파", "해수면상승", "해일", "홍수", "황사", "호우", "화산폭발", "우주전파재난", "우주물체추락"] + + var buttonImages = [UIImage(named: "Drought"), UIImage(named: "Strong wind"), UIImage(named:"Lightning"), UIImage(named:"Green tide"), UIImage(named:"Heavy snow"), UIImage(named:"Landslide"), UIImage(named:"Red tide"), UIImage(named:"Earthquake"), UIImage(named:"Earthquake and tsunami"), UIImage(named:"Flooding"), UIImage(named:"Typhoon"), UIImage(named:"Heat wave"), UIImage(named:"Rough sea"), UIImage(named:"Cold wave"), UIImage(named:"Sea level rise"), UIImage(named:"Tsunami"), UIImage(named:"Flood"), UIImage(named:"Dust storm"), UIImage(named:"Heavy rain"), UIImage(named:"Volcanic eruption"), UIImage(named:"Space radio disaster"), UIImage(named:"Natural space object crash")] + + let titleLabel: UILabel = { + let label = UILabel() + label.text = "카테고리" + label.font = UIFont.systemFont(ofSize: 30, weight: .bold) + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + let collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) + cv.translatesAutoresizingMaskIntoConstraints = false + cv.register(CategoryCell.self, forCellWithReuseIdentifier: "cell") + return cv + }() + + + var pageController: UIPageControl = { + let pageControl = UIPageControl() + pageControl.numberOfPages = 3 + pageControl.currentPage = 0 + pageControl.pageIndicatorTintColor = .gray + pageControl.currentPageIndicatorTintColor = .darkGray + pageControl.translatesAutoresizingMaskIntoConstraints = false + + return pageControl + }() + + override func viewDidLoad() { + super.viewDidLoad() + setData() + view.backgroundColor = .white + + view.addSubview(titleLabel) + view.addSubview(collectionView) + view.addSubview(pageController) + + collectionView.delegate = self + collectionView.dataSource = self + collectionView.isPagingEnabled = true + collectionView.showsHorizontalScrollIndicator = false + + pageController.addTarget(self, action: #selector(handlePageControl(_:)), for: .valueChanged) + + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50), + titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor), + + collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 40), + collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30), + collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30), + collectionView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5), + + pageController.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 30), + pageController.leadingAnchor.constraint(equalTo: view.leadingAnchor), + pageController.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + } + + func setData() { + DispatchQueue.global(qos: .userInteractive).async { + print("About to call getCategoryData") + + self.categoryApiHandler.getCategoryData() { [weak self] data in + guard let self = self else { return } + print("getCategoryData completion handler called") + + + DispatchQueue.main.async { + self.categoryData = data // CategoryModel 배열 데이터 저장 + self.collectionView.reloadData() // 컬렉션 뷰 리로드 + } + } + } + } + + @objc func handlePageControl(_ sender: UIPageControl) { + let currentPage = sender.currentPage + let x = CGFloat(currentPage) * collectionView.frame.width + collectionView.setContentOffset(CGPoint(x: x, y: 0), animated: true) + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + let pageIndex = round(scrollView.contentOffset.x/collectionView.frame.width) + pageController.currentPage = Int(pageIndex) + } + + func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { + let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout + let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing + + var offset = targetContentOffset.pointee + let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing + let roundedIndex = round(index) + + offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top) + targetContentOffset.pointee = offset + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CategoryCell + + if let categoryModelData = categoryData { + let labelToKey: [String: CategoryModel.CodingKeys] = [ + "가뭄": .drought, + "강풍": .strongWind, + "낙뢰": .lightning, + "녹조": .greenTide, + "대설": .heavySnow, + "산사태": .landslide, + "적조": .redTide, + "지진": .earthquake, + "지진해일": .tsunami, + "침수": .flooding, + "태풍": .typhoon, + "폭염": .heatWave, + "풍랑": .windAndWaves, + "한파": .coldWave, + "해수면상승": .risingSeaLevel, + "해일": .tidalWave, + "홍수": .flood, + "황사": .yellowDust, + "호우": .heavyRain, + "화산폭발": .volcanicEruption, + "우주전파재난": .spacePropagationDisaster, + "우주물체추락": .theFallOfNaturalSpaceObjects + ] + + if indexPath.row < buttonLabels.count { + let buttonLabel = buttonLabels[indexPath.row] + let buttonImage = buttonImages[indexPath.row] + cell.categoryView.buttonLabel.text = buttonLabel + cell.categoryView.buttonImageView.image = buttonImage + + cell.categoryView.buttonAction = { [weak self] in + guard let self = self, + let buttonLabel = cell.categoryView.buttonLabel.text, + let key = labelToKey[buttonLabel]?.stringValue else { return } + print("key : \(key)") + + // key를 category로 전달 +// self.categoryPageApiHandler.getCategoryPageData(category: key) { [weak self] data in +// guard let self = self else { return } +// // 정의해둔 모델 객체에 할당 +// self.categoryPageViewController.categoryPageData = data +// +// // 데이터를 제대로 잘 받아왔다면 +// guard let data = self.categoryPageViewController.categoryPageData else { +// return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") +// } +// +// DispatchQueue.main.async { +// let categoryPageViewController = CategoryPageViewController() +// categoryPageViewController.presentCategory = key +// +// let categoryViewController = CategoryViewController() +// let navigationController = UINavigationController(rootViewController: categoryViewController) +// UIApplication.shared.windows.first?.rootViewController = navigationController +// navigationController.pushViewController(categoryPageViewController, animated: true) +// } +// } + } + } + } + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + let totalCells = buttonImages.count + let remainder = totalCells % 9 + return totalCells + (remainder > 0 ? (9 - remainder) : 0) // 빈 셀 추가 + } + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + + let width = collectionView.frame.width / 3 + let height = collectionView.frame.height / 3 + return CGSize(width: width, height: height) + } +} diff --git a/Helfy/Controller/CorrectOrWrongViewController.swift b/Helfy/Controller/CorrectOrWrongViewController.swift new file mode 100644 index 0000000..74bb13f --- /dev/null +++ b/Helfy/Controller/CorrectOrWrongViewController.swift @@ -0,0 +1,50 @@ +// +// CorrectOrWrongViewController.swift +// Helfy +// +// Created by 윤성은 on 1/7/24. +// + +import UIKit + +enum AnswerType { + case correct + case wrong +} + +class CorrectOrWrongViewController: UIViewController { + var answerType: AnswerType + + let iconLabel = UILabel() + + init(answerType: AnswerType) { + self.answerType = answerType + super.init(nibName: nil, bundle: nil) + setUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setUI() { + iconLabel.textAlignment = .center + iconLabel.font = UIFont.systemFont(ofSize: 100) + + switch answerType { + case .correct: + iconLabel.text = "✅" + case .wrong: + iconLabel.text = "❌" + } + + view.addSubview(iconLabel) + + // 레이아웃 설정 + iconLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + iconLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + iconLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } +} diff --git a/Helfy/Controller/EditModalViewController.swift b/Helfy/Controller/EditModalViewController.swift new file mode 100644 index 0000000..6eb28d4 --- /dev/null +++ b/Helfy/Controller/EditModalViewController.swift @@ -0,0 +1,245 @@ +// +// EditModalViewController.swift +// Helfy +// +// Created by 윤성은 on 1/31/24. +// + +import UIKit + +class EditModalViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate { + var myPageApiHandler : MyPageAPIHandler = MyPageAPIHandler() + var onConfirm: ((String?, String?) -> Void)? + var textViewTag: Int = 0 + + let regionDictionary: [String: String] = [ + "SEOUL" : "서울", + "GYEONGGI" : "경기", + "INCHEON" : "인천", + "BUSAN" : "부산", + "JEJU" : "제주", + "ULSAN" : "울산", + "GYEONGSANGNAM" : "경남", + "DAEGU" : "대구", + "GYEONGSANGBUK" : "경북", + "GANGWON" : "강원", + "DAEJEON" : "대전", + "CHUNGCHEONGNAM" : "충남", + "CHUNGCHEONGBUK" : "충북", + "SEJONG" : "세종", + "GWANGJU" : "광주", + "JEOLANAM" : "전남", + "JEOLABUK" : "전북" + ] + + var nickname: String? + var region: String? + + let textField: UITextField = { + let textField = UITextField() + textField.font = UIFont.systemFont(ofSize: 25) + textField.textColor = UIColor.white + textField.backgroundColor = UIColor.clear + textField.textAlignment = .center + textField.clearButtonMode = .always + textField.autocapitalizationType = .none + textField.spellCheckingType = .no + textField.translatesAutoresizingMaskIntoConstraints = false + return textField + }() + + let separatorView: UIView = { + let view = UIView() + view.backgroundColor = .gray + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + let textCountLabel: UILabel = { + let label = UILabel() + label.textColor = UIColor.white + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + lazy var regionButton: UIButton = { + let button = UIButton() + button.setTitle(regionDictionary[region ?? ""], for: .normal) + button.titleLabel?.font = .systemFont(ofSize: 25) + button.addTarget(self, action: #selector(regionButtonTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + let cancelButton: UIButton = { + let button = UIButton() + button.setTitle("취소", for: .normal) + button.setTitleColor(.white, for: .normal) + button.addTarget(self, action: #selector(cancelButtonTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + let confirmButton: UIButton = { + let button = UIButton() + button.setTitle("확인", for: .normal) + button.setTitleColor(.white, for: .normal) + button.addTarget(self, action: #selector(confirmButtonTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + setupUI() + + textField.delegate = self + textField.text = nickname + textCountLabel.text = "\(textField.text?.count ?? 0) / 15" + } + + private func setupUI() { + view.addSubview(textField) + view.addSubview(separatorView) + view.addSubview(textCountLabel) + view.addSubview(regionButton) + view.addSubview(cancelButton) + view.addSubview(confirmButton) + + NSLayoutConstraint.activate([ + textField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200), + textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + textField.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + separatorView.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 10), + separatorView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + separatorView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8), + separatorView.heightAnchor.constraint(equalToConstant: 1), + + // textCountLabel의 제약 조건 + textCountLabel.topAnchor.constraint(equalTo: separatorView.bottomAnchor, constant: 10), + textCountLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + // regionButton의 제약 조건 + regionButton.topAnchor.constraint(equalTo: textCountLabel.bottomAnchor, constant: 50), + regionButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + regionButton.widthAnchor.constraint(equalToConstant: 200), + regionButton.heightAnchor.constraint(equalToConstant: 100), + + cancelButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15), + cancelButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + + confirmButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15), + confirmButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + ]) + + self.view.backgroundColor = UIColor(white: 0.2, alpha: 0.9) + + } + + @objc func regionButtonTapped() { + let alert = UIAlertController(title: "지역 선택", message: "지역을 선택해주세요.", preferredStyle: .actionSheet) + + for (key, value) in regionDictionary { + alert.addAction(UIAlertAction(title: value, style: .default, handler: { [weak self] _ in + // regionDictionary를 사용하여 영어 지역명을 한글로 변환하여 title로 설정합니다. + self?.regionButton.setTitle(value, for: .normal) + // 지역이 변경되었으므로 확인 버튼을 활성화합니다. + self?.confirmButton.isEnabled = true + self?.confirmButton.setTitleColor(.white, for: .normal) + })) + } + + alert.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil)) + + self.present(alert, animated: true, completion: nil) + } + + @objc func confirmButtonTapped() { + let nickname = textField.text ?? "" + let regionTitle = regionButton.title(for: .normal) ?? "" + let region = regionDictionary.first { $1 == regionTitle }?.key ?? "" + + myPageApiHandler.updateMyPageData(nickname: nickname, region: region) { [weak self] success in + + if success { + self?.onConfirm?(nickname, region) + } else { + print("Failed to update data.") + } + } + + self.dismiss(animated: true, completion: nil) + } + + @objc func cancelButtonTapped() { + self.dismiss(animated: true, completion: nil) + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + let currentText = textField.text ?? "" + guard let stringRange = Range(range, in: currentText) else { return false } + let updatedText = currentText.replacingCharacters(in: stringRange, with: string) + + textCountLabel.text = "\(updatedText.count) / 15" + + // 확인 버튼의 상태를 업데이트 +// confirmButton.isEnabled = !updatedText.isEmpty +// confirmButton.setTitleColor(updatedText.isEmpty ? .gray : .white, for: .normal) + + return updatedText.count < 15 + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + textCountLabel.text = "0 / 15" + + // 확인 버튼의 상태를 업데이트 + confirmButton.isEnabled = false + confirmButton.setTitleColor(.gray, for: .normal) + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + print("Before end editing: \(textField.text)") + textField.endEditing(true) + print("After end editing: \(textField.text)") + + return false + } + + internal func textFieldDidEndEditing(_ textField: UITextField) { + if let text = textField.text { + print("사용자가 입력한 텍스트: \(text)") + nickname = text + } + } + + func setUpKeyboard() { + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) + } + + @objc func keyboardWillShow(notification: NSNotification) { + if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil { + + if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { + + confirmButton.isEnabled = false + + UIView.animate(withDuration: 0.3) { + self.view.layoutIfNeeded() + } + } + } + } + + @objc func keyboardWillHide(notification: NSNotification) { + confirmButton.isEnabled = true + UIView.animate(withDuration: 0.3) { + self.view.layoutIfNeeded() + } + } +} diff --git a/Helfy/Controller/Login/FirebaseAuth.swift b/Helfy/Controller/Login/FirebaseAuth.swift index d10ebb5..a5c5dfd 100644 --- a/Helfy/Controller/Login/FirebaseAuth.swift +++ b/Helfy/Controller/Login/FirebaseAuth.swift @@ -28,7 +28,6 @@ extension LoginViewController { print("Failed to login with Firebase: ", error) return } - self.showMainViewController() } @@ -43,6 +42,8 @@ extension LoginViewController { print("ID token is nil") return } + UserDefaults.standard.set(idToken, forKey: "GoogleToken") + print("sendIDTokenToServer 저장 완료 \n UserDefaults : \(idToken)") sendIDTokenToServer(idToken) }) diff --git a/Helfy/Controller/Login/LoginViewController.swift b/Helfy/Controller/Login/LoginViewController.swift index c60552e..974f9eb 100644 --- a/Helfy/Controller/Login/LoginViewController.swift +++ b/Helfy/Controller/Login/LoginViewController.swift @@ -65,11 +65,16 @@ class LoginViewController : UIViewController { guard let user = user?.user, let idToken = user.idToken?.tokenString else { return } + + let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: user.accessToken.tokenString) +// print(credential.accesst) + // UserDefaults에 토큰 값을 저장합니다. self.firebaseLogin(credential) } } + } extension LoginViewController: ASAuthorizationControllerDelegate { diff --git a/Helfy/Controller/MainViewController.swift b/Helfy/Controller/MainViewController.swift index 908e183..f110a1c 100644 --- a/Helfy/Controller/MainViewController.swift +++ b/Helfy/Controller/MainViewController.swift @@ -10,75 +10,210 @@ import FirebaseAuth import GoogleSignIn class MainViewController: UIViewController { + let categoryViewController = CategoryViewController() + + let mainView = MainView() - let welcomeLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 0 - label.textAlignment = .center - return label - }() - - let logoutButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle("로그아웃", for: .normal) - button.addTarget(self, action: #selector(tapLogoutButton), for: .touchUpInside) - return button - }() + var mainApiHandler : MainAPIHandler = MainAPIHandler() + var mainModelData: MainModel? { + didSet { + print("hi") + } + } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.navigationBar.isHidden = true + override func viewDidLoad() { + super.viewDidLoad() - let email = Auth.auth().currentUser?.email ?? "고객" + setUI() + setData() - welcomeLabel.text = """ - 환영합니다. - \(email)님 - """ + NotificationCenter.default.addObserver(self, selector: #selector(handleProfileUpdate), name: Notification.Name("profileUpdated"), object: nil) + + // CategoryViewController를 메인뷰에 추가합니다. + addChild(categoryViewController) +// view.addSubview(categoryViewController.view) + categoryViewController.didMove(toParent: self) + + // CategoryViewController.view의 위치와 크기를 설정합니다. +// categoryViewController.view.frame = view.frame // 원하는 위치와 크기로 설정 + + mainView.profileImageView.isUserInteractionEnabled = true + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(openMyPage)) + mainView.profileImageView.addGestureRecognizer(tapGesture) } - override func viewDidLoad() { - super.viewDidLoad() + func setData() { + DispatchQueue.global(qos: .userInteractive).async { + // API 통해 데이터 불러오기 + self.mainApiHandler.getMainData() { [weak self] data in + guard let self = self else { return } + // 정의해둔 모델 객체에 할당 + self.mainModelData = data + + // 데이터를 제대로 잘 받아왔다면 + guard let data = self.mainModelData else { + return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") + } + + DispatchQueue.main.async { + self.mainView.nicknameLabel.text = data.userInfo.nickname + self.updateWeatherImageView(with: data.weatherInfo.weatherCode) // 이미지 뷰의 이미지를 갱신합니다. + self.mainView.weatherLabel.text = "\(data.weatherInfo.temp)℃ \(data.weatherInfo.humidity)%" + } + } + } + } + + func setUI() { view.backgroundColor = .white - navigationController?.interactivePopGestureRecognizer?.isEnabled = false - // pop 불가 - - view.addSubview(welcomeLabel) - view.addSubview(logoutButton) - - welcomeLabel.translatesAutoresizingMaskIntoConstraints = false - logoutButton.translatesAutoresizingMaskIntoConstraints = false - + view.addSubview(mainView) + view.addSubview(categoryViewController.view) + + mainView.translatesAutoresizingMaskIntoConstraints = false + categoryViewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ - welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - welcomeLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), - logoutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - logoutButton.topAnchor.constraint(equalTo: welcomeLabel.bottomAnchor, constant: 20) + // mainView의 제약 설정 + mainView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + mainView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + mainView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + mainView.bottomAnchor.constraint(equalTo: categoryViewController.view.topAnchor, constant: -100), + + categoryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30), + categoryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30), + categoryViewController.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5), + categoryViewController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) } + + @objc func openMyPage() { + print("😀😀😀😀😀😀😀😀😀") + let myPageViewController = MypageViewController() + let mainViewController = MainViewController() + let navigationController = UINavigationController(rootViewController: mainViewController) + UIApplication.shared.windows.first?.rootViewController = navigationController + navigationController.pushViewController(myPageViewController, animated: true) + } - @objc func tapLogoutButton() { - - let firebaseAuth = Auth.auth() - do { - // google logout - GIDSignIn.sharedInstance.signOut() - try firebaseAuth.signOut() - self.navigationController?.popToRootViewController(animated: true) - print("popToRootViewController") - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { - if let window = windowScene.windows.first { - let navigationController = UINavigationController(rootViewController: LoginViewController()) - UIView.transition(with: window, duration: 0.5, options: .transitionFlipFromRight, animations: { - window.rootViewController = navigationController - }, completion: nil) - } + @objc func handleProfileUpdate(notification: NSNotification) { + DispatchQueue.main.async { [weak self] in + if let userInfo = notification.userInfo, let nickname = userInfo["nickname"] as? String { + self?.mainView.nicknameLabel.text = nickname } - } catch let signOutError as NSError { - print("ERROR: signOutError \(signOutError.localizedDescription)") } } + + func updateWeatherImageView(with weatherCode: String) { + let systemName: String + switch weatherCode { + case "THUNDERSTORM": + systemName = "cloud.bolt.rain.fill" // 번개 이미지 + case "DRIZZLE": + systemName = "cloud.drizzle.fill" // 이슬비 이미지 + case "RAIN": + systemName = "cloud.rain.fill" // 비 이미지 + case "SNOW": + systemName = "cloud.snow.fill" // 눈 이미지 + case "ATMOSPHERE": + systemName = "cloud.fog.fill" // 대기 이미지 + case "CLEAR": + systemName = "sun.max.fill" // 맑음 이미지 + case "CLOUDS": + systemName = "cloud.fill" // 구름 이미지 + default: + systemName = "questionmark.diamond.fill" // 기본 이미지 + } + + mainView.weatherImageView.image = UIImage(systemName: systemName)?.withTintColor(.darkGray, renderingMode: .alwaysOriginal) + } } + +// @objc private func openMyPage() { +// print("😀😀😀😀😀😀😀😀😀") +// +// let myPageViewController = MypageViewController() +// myPageViewController.modalPresentationStyle = .fullScreen +// self.present(myPageViewController, animated: true, completion: nil) +// } + +// @objc private func openMyPage() { +// print("😀😀😀😀😀😀😀😀😀") +// let myPageViewController = MypageViewController() +// self.navigationController?.pushViewController(myPageViewController, animated: true) +// } + +//class MainViewController: UIViewController { +// +// let welcomeLabel: UILabel = { +// let label = UILabel() +// label.numberOfLines = 0 +// label.textAlignment = .center +// return label +// }() +// +// let logoutButton: UIButton = { +// let button = UIButton(type: .system) +// button.setTitle("로그아웃", for: .normal) +// button.addTarget(self, action: #selector(tapLogoutButton), for: .touchUpInside) +// return button +// }() +// +// override func viewWillAppear(_ animated: Bool) { +// super.viewWillAppear(animated) +// navigationController?.navigationBar.isHidden = true +// +// let email = Auth.auth().currentUser?.email ?? "고객" +// +// welcomeLabel.text = """ +// 환영합니다. +// \(email)님 +// """ +// } +// +// override func viewDidLoad() { +// super.viewDidLoad() +// view.backgroundColor = .white +// +// navigationController?.interactivePopGestureRecognizer?.isEnabled = false +// // pop 불가 +// +// view.addSubview(welcomeLabel) +// view.addSubview(logoutButton) +// +// welcomeLabel.translatesAutoresizingMaskIntoConstraints = false +// logoutButton.translatesAutoresizingMaskIntoConstraints = false +// +// NSLayoutConstraint.activate([ +// welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), +// welcomeLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), +// logoutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), +// logoutButton.topAnchor.constraint(equalTo: welcomeLabel.bottomAnchor, constant: 20) +// ]) +// } +// +// @objc func tapLogoutButton() { +// +// let firebaseAuth = Auth.auth() +// do { +// // google logout +// GIDSignIn.sharedInstance.signOut() +// try firebaseAuth.signOut() +// self.navigationController?.popToRootViewController(animated: true) +// print("popToRootViewController") +// +// if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { +// if let window = windowScene.windows.first { +// let navigationController = UINavigationController(rootViewController: LoginViewController()) +// UIView.transition(with: window, duration: 0.5, options: .transitionFlipFromRight, animations: { +// window.rootViewController = navigationController +// }, completion: nil) +// } +// } +// } catch let signOutError as NSError { +// print("ERROR: signOutError \(signOutError.localizedDescription)") +// } +// } +//} +// diff --git a/Helfy/Controller/MypageViewController.swift b/Helfy/Controller/MypageViewController.swift index 0e01049..f576cc1 100644 --- a/Helfy/Controller/MypageViewController.swift +++ b/Helfy/Controller/MypageViewController.swift @@ -6,62 +6,107 @@ // import UIKit -import MessageUI +import FirebaseAuth +import GoogleSignIn -class MypageViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate { +class MypageViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate { let myPageView = MypageView() let imagePicker = UIImagePickerController() - - private let myPageModel: MypageModel - private let user: User2 - - init(user: User2) { - self.user = user - self.myPageModel = MypageModel(user: user) - super.init(nibName: nil, bundle: nil) - - myPageView.tableView.delegate = self - myPageView.tableView.dataSource = self - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + let editModalViewController = EditModalViewController() + + // 수정 버튼 + let editButton: UIButton = { + let button = UIButton() + let configuration = UIImage.SymbolConfiguration(pointSize: 30, weight: .bold) + button.setImage(UIImage(systemName: "pencil", withConfiguration: configuration)?.withTintColor(UIColor(hex: "#F9A456"), renderingMode: .alwaysOriginal), for: .normal) + button.addTarget(self, action: #selector(editButtonTapped), for: .touchUpInside) + return button + }() + + // 로그아웃 버튼 + let logoutButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("로그아웃", for: .normal) + button.setTitleColor(UIColor(hex: "#F9A456"), for: .normal) + button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 25) + button.addTarget(self, action: #selector(tapLogoutButton), for: .touchUpInside) + return button + }() + + var myPageApiHandler : MyPageAPIHandler = MyPageAPIHandler() + var myPageModelData: MypageModel? { + didSet { + print("hi") + } } - + override func viewDidLoad() { super.viewDidLoad() + setupUI() - myPageView.updateUserUI(user: user) + + // 프로필 이미지 변경 버튼에 대한 액션 설정 + myPageView.profileImageView.isUserInteractionEnabled = true + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(openImagePicker)) + myPageView.profileImageView.addGestureRecognizer(tapGesture) + + // 프로필 이미지에 대한 액션 설정 + let tapGestureImage = UITapGestureRecognizer(target: self, action: #selector(openImagePicker)) + myPageView.profileImageView.addGestureRecognizer(tapGestureImage) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + print(myPageView) + + DispatchQueue.global(qos: .userInteractive).async { + // API 통해 데이터 불러오기 + self.myPageApiHandler.getMyPageData() { [weak self] data in + guard let self = self else { return } + // 정의해둔 모델 객체에 할당 + self.myPageModelData = data + + // 데이터를 제대로 잘 받아왔다면 + guard let data = self.myPageModelData else { + return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") + } + + DispatchQueue.main.async { + self.myPageView.nicknameLabel.text = data.userInfo.nickname + let regionInKorean = self.editModalViewController.regionDictionary[data.userInfo.region] ?? data.userInfo.region + self.myPageView.regionLabel.text = regionInKorean + self.myPageView.rankLabel.text = String(data.rankInfo.rank) + self.myPageView.scoreLabel.text = String(data.rankInfo.score) + } + } + } } private func setupUI() { view.addSubview(myPageView) + view.addSubview(editButton) + view.addSubview(logoutButton) myPageView.translatesAutoresizingMaskIntoConstraints = false - + editButton.translatesAutoresizingMaskIntoConstraints = false + logoutButton.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + editButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + editButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + myPageView.topAnchor.constraint(equalTo: view.topAnchor), myPageView.bottomAnchor.constraint(equalTo: view.bottomAnchor), myPageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - myPageView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + myPageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + + logoutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + logoutButton.topAnchor.constraint(equalTo: myPageView.containerStackView.bottomAnchor, constant: 100), ]) - - view.backgroundColor = .white - - // 프로필 이미지 변경 버튼에 대한 액션 설정 - myPageView.profileImageView.isUserInteractionEnabled = true - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(openImagePicker)) - myPageView.profileImageView.addGestureRecognizer(tapGesture) - // 프로필 이미지에 대한 액션 설정 - let tapGestureImage = UITapGestureRecognizer(target: self, action: #selector(openImagePicker)) - myPageView.profileImageView.addGestureRecognizer(tapGestureImage) - - // 버튼(닉네임 변경, 지역 변경, 로그아웃)에 대한 액션 설정 - myPageView.changeNicknameButton.addTarget(self, action:#selector(didTapChangeNicknameButton), for:.touchUpInside) - myPageView.changeLocationButton.addTarget(self, action:#selector(didTapChangeLocationButton), for:.touchUpInside) - myPageView.logoutButton.addTarget(self, action:#selector(didTapLogoutButton), for:.touchUpInside) + view.backgroundColor = .white } // 이미지를 누르면 변경할 수 있는 버튼 @@ -72,12 +117,17 @@ class MypageViewController: UIViewController, UIImagePickerControllerDelegate, U imagePicker.allowsEditing = true present(imagePicker, animated: true, completion: nil) } + + // 프로필 이미지 업데이트 + func updateProfileImage(_ image: UIImage) { + myPageView.profileImageView.image = image + } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { if let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage { - myPageView.updateProfileImage(selectedImage) + self.updateProfileImage(selectedImage) } else if let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { - myPageView.updateProfileImage(selectedImage) + self.updateProfileImage(selectedImage) } picker.dismiss(animated: true, completion: nil) } @@ -87,67 +137,48 @@ class MypageViewController: UIViewController, UIImagePickerControllerDelegate, U picker.dismiss(animated: true, completion: nil) } - @objc private func didTapChangeNicknameButton() { - print("닉네임 변경 버튼이 눌렸습니다.") - } - - @objc private func didTapChangeLocationButton() { - print("지역 변경 버튼이 눌렸습니다.") - } - - @objc private func didTapLogoutButton() { - print("로그아웃 버튼이 눌렸습니다.") - } - - @objc private func didTableButton() { - print("테이블 버튼이 눌렸습니다.") - } - - // tableView 설정 - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return myPageView.buttons.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCell", for: indexPath) - cell.textLabel?.text = myPageView.buttons[indexPath.row] - cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 22) - cell.textLabel?.textColor = UIColor.black - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let selectedButton = myPageView.buttons[indexPath.row] - switch selectedButton { - case "뭐1": - didTableButton() - case "뭐2": - didTableButton() - case "뭐3": - didTableButton() - case "뭐4": - didTableButton() - case "문의": - // "문의" 셀을 선택했을 때 - if MFMailComposeViewController.canSendMail() { - let mailComposeViewController = MFMailComposeViewController() - mailComposeViewController.mailComposeDelegate = self - mailComposeViewController.setToRecipients(["Helfy@gmail.com"]) - mailComposeViewController.setSubject("문의") // 여기에 메일 제목을 설정하세요. - - self.present(mailComposeViewController, animated: true, completion: nil) - } else { - print("이 장치에서는 메일을 보낼 수 없습니다.") + @objc func editButtonTapped() { + editModalViewController.modalPresentationStyle = .fullScreen + editModalViewController.modalPresentationStyle = .overCurrentContext + editModalViewController.modalTransitionStyle = .crossDissolve + editModalViewController.nickname = myPageModelData?.userInfo.nickname + editModalViewController.region = myPageModelData?.userInfo.region + + editModalViewController.onConfirm = { [weak self] nickname, region in + // 서버에서 최신 데이터를 받아옵니다. + self?.myPageApiHandler.getMyPageData() { data in + self?.myPageModelData = data + DispatchQueue.main.async { + self?.myPageView.nicknameLabel.text = data.userInfo.nickname + let regionInKorean = self?.editModalViewController.regionDictionary[region ?? ""] ?? region + self?.myPageView.regionLabel.text = regionInKorean + } } - - default: - break } + + present(editModalViewController, animated: true, completion: nil) } + - // 메일 작성을 완료하거나 취소했을 때 호출되는 메소드 - @objc(mailComposeController:didFinishWithResult:error:) func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { - controller.dismiss(animated: true, completion: nil) + @objc func tapLogoutButton() { + let firebaseAuth = Auth.auth() + do { + // google logout + GIDSignIn.sharedInstance.signOut() + try firebaseAuth.signOut() + self.navigationController?.popToRootViewController(animated: true) + print("popToRootViewController") + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + if let window = windowScene.windows.first { + let navigationController = UINavigationController(rootViewController: LoginViewController()) + UIView.transition(with: window, duration: 0.5, options: .transitionFlipFromRight, animations: { + window.rootViewController = navigationController + }, completion: nil) + } + } + } catch let signOutError as NSError { + print("ERROR: signOutError \(signOutError.localizedDescription)") + } } } diff --git a/Helfy/Controller/QuestionViewController.swift b/Helfy/Controller/QuestionViewController.swift deleted file mode 100644 index 6a5fc95..0000000 --- a/Helfy/Controller/QuestionViewController.swift +++ /dev/null @@ -1,140 +0,0 @@ -// -// QuestionViewController.swift -// Helfy -// -// Created by 윤성은 on 11/22/23. -// - -import UIKit - -class QuestionViewController: UIViewController { - var questionView: QuestionView! - var choiceView: ChoiceView! - var currentQuestionIndex = 0 - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .white - - let text = "지진이 났을 때, 하지말아야할 행동으로 운동장으로 뛰어간다는 맞을까요~ 틀릴까요~? 태풍이 오고 있을 때 창문에 테이프를 엑스로 붙여야할까요 세로나 가로로 붙여야할까요~?" -// let imageUrlString = "" - let image: UIImage? = UIImage(systemName: "square.and.arrow.up") -// let data: [String: Any] = ["text": "Sample Question", "choices": ["맞다, 엑스", "틀리다, 엑스", "맞다, 세로나 가로", "틀리다, 세로나 가로"], "answerIndex": 1, "image": image] -// let type: QuestionType = .MultipleQuestion - - let data: [String: Any] = ["text": "Sample Question", "answer": true, "image": image] - - let type: QuestionType = .TrueOrFalseQuestion - - addChoiceView(data: data, type: type) - - if let image = UIImage(systemName: "square.and.arrow.up") { - addQuestionView(text: text, image: image) - } else { - // 이미지 로드 중 에러가 발생한 경우 - print("이미지 로드 에러") - } - -// if let imageUrl = URL(string: imageUrlString) { -// URLSession.shared.dataTask(with: imageUrl) { (data, response, error) in -// if let error = error { -// print("Error downloading image: \(error)") -// } else if let data = data { -// DispatchQueue.main.async { -// self.addQuestionView(text: text, image: UIImage(data: data)) -// } -// } -// }.resume() -// } - } - - func addChoiceView(data: [String: Any], type: QuestionType) { - // 객관식 - if type == .MultipleQuestion { - let multipleChoiceView = MultipleChoiceView(question: MultipleChoiceQuestion.dictionaryMultiple(data: data)) - choiceView = multipleChoiceView - choiceView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(choiceView) - NSLayoutConstraint.activate([ - choiceView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), - choiceView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), - choiceView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), - choiceView.heightAnchor.constraint(equalToConstant: 270) - ]) - choiceView.display() - for button in multipleChoiceView.choiceButtons { - button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) - } - } else { - // true or false - choiceView = TrueOrFalseQuestionView(question: TrueOrFalseQuestion.dictionaryTrueOrFalse(data: data)) - choiceView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(choiceView) - NSLayoutConstraint.activate([ - choiceView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), - choiceView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), - choiceView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), - choiceView.heightAnchor.constraint(equalToConstant: 250) - ]) - - choiceView.display() - if let trueOrFalseView = choiceView as? TrueOrFalseQuestionView { - trueOrFalseView.trueButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) - trueOrFalseView.falseButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) - } - } - } - - func addQuestionView(text: String, image: UIImage?) { - questionView = QuestionView(text: text, image: nil) - questionView.translatesAutoresizingMaskIntoConstraints = false - self.view.addSubview(questionView) - - // QuestionView에 대한 제약 조건 설정 - NSLayoutConstraint.activate([ - questionView.topAnchor.constraint(equalTo: self.view.topAnchor), - questionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), - questionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), - questionView.bottomAnchor.constraint(equalTo: choiceView.topAnchor, constant: -10), - ]) - } - - @objc func buttonTapped(_ sender: UIButton) { - // 사용자의 선택 저장 - let userChoice = sender.tag // 각 버튼에 고유한 태그를 부여하여 구분 - - // 답안 체크 - let isCorrect = checkAnswer(userChoice: userChoice) - - // 답안에 따른 버튼 색상 변경 - if isCorrect == true { - sender.backgroundColor = UIColor.systemGreen - } else { - sender.backgroundColor = UIColor.red - } - // 정답이 맞으면 다음 문제 로드 - loadNextQuestion() - } - - func checkAnswer(userChoice: Int) -> Bool { - // MultipleChoiceQuestion 타입의 경우 - if let multipleChoiceView = choiceView as? MultipleChoiceView { - let correctAnswer = multipleChoiceView.question.answerIndex - return userChoice == correctAnswer // 여기를 수정하였습니다. - } - // TrueOrFalseQuestion 타입의 경우 - else if let trueOrFalseView = choiceView as? TrueOrFalseQuestionView { - let correctAnswer = trueOrFalseView.question.answer - return userChoice == (correctAnswer ? 1 : 0) - } - // 위의 경우가 아닌 경우 - else { - return false - } - } - - func loadNextQuestion() { - - } - -} diff --git a/Helfy/Controller/Quiz/CorrectOrWrongViewController.swift b/Helfy/Controller/Quiz/CorrectOrWrongViewController.swift new file mode 100644 index 0000000..056f712 --- /dev/null +++ b/Helfy/Controller/Quiz/CorrectOrWrongViewController.swift @@ -0,0 +1,52 @@ +// +// CorrectOrWrongViewController.swift +// Helfy +// +// Created by 윤성은 on 1/7/24. +// + +import UIKit + +enum AnswerType { + case correct + case wrong +} + +class CorrectOrWrongViewController: UIViewController { + var answerType: AnswerType + var id: String + + let iconLabel = UILabel() + + init(answerType: AnswerType, id: String) { + self.answerType = answerType + self.id = id + super.init(nibName: nil, bundle: nil) + setUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setUI() { + iconLabel.textAlignment = .center + iconLabel.font = UIFont.systemFont(ofSize: 100) + + switch answerType { + case .correct: + iconLabel.text = "⭕️" + case .wrong: + iconLabel.text = "❌" + } + + view.addSubview(iconLabel) + + // 레이아웃 설정 + iconLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + iconLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + iconLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } +} diff --git a/Helfy/Controller/Quiz/DoQuizViewController.swift b/Helfy/Controller/Quiz/DoQuizViewController.swift new file mode 100644 index 0000000..fd69285 --- /dev/null +++ b/Helfy/Controller/Quiz/DoQuizViewController.swift @@ -0,0 +1,30 @@ +// +// DoQuizViewController.swift +// Helfy +// +// Created by 윤성은 on 1/4/24. +// + +import UIKit + +class DoQuizViewController: UIViewController { + let quizVC = QuizViewController() + + override func viewDidLoad() { + super.viewDidLoad() + + addChild(quizVC) + view.addSubview(quizVC.view) + quizVC.didMove(toParent: self) + quizVC.setData(quizCategory: "NORMAL") + quizVC.quizCategory = "NORMAL" + + quizVC.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + quizVC.view.topAnchor.constraint(equalTo: view.topAnchor), + quizVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + quizVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + quizVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) + } +} diff --git a/Helfy/Controller/Quiz/QuizHomeViewController.swift b/Helfy/Controller/Quiz/QuizHomeViewController.swift new file mode 100644 index 0000000..9bbe12d --- /dev/null +++ b/Helfy/Controller/Quiz/QuizHomeViewController.swift @@ -0,0 +1,90 @@ +// +// QuizViewController.swift +// Helfy +// +// Created by 윤성은 on 2023/10/06. + +import UIKit + +class QuizHomeViewController: UIViewController { + let quizHomeView = QuizHomeView() + var quizApiHandler : QuizAPIHandler = QuizAPIHandler() + let quizViewController = QuizViewController() + var quizHomeModelData: QuizHomeModel? { + didSet { + print("Hi") + } + } + + override func viewDidLoad() { + super.viewDidLoad() + setData() + +// if let tabBarViewController = parent as? TabBarViewController { +// print(tabBarViewController.selectedIndex) +// } + + view.addSubview(quizHomeView) + + quizHomeView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + quizHomeView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + quizHomeView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), + quizHomeView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + quizHomeView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + ]) + + quizHomeView.todayButton.addTarget(self, action:#selector(openTodayQuiz), for:.touchUpInside) + quizHomeView.quizButton.addTarget(self, action:#selector(openDoQuiz), for:.touchUpInside) + quizHomeView.wrongButton.addTarget(self, action:#selector(openWrongQuiz), for:.touchUpInside) + } + + func setData() { + DispatchQueue.global(qos: .userInteractive).async { + + // API 통해 데이터 불러오기 + self.quizApiHandler.getQuizHomeData() { [self] data in + // 정의해둔 모델 객체에 할당 + self.quizHomeModelData = data + + // 데이터를 제대로 잘 받아왔다면 + guard let data = self.quizHomeModelData else { + + return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") + } + + DispatchQueue.main.async { + self.quizHomeView.idLabel.text = data.nickname + " 님" + self.quizHomeView.scoreLabel.text = "나의 점수 : " + String(data.score) + } + } + } + } + + @objc func openTodayQuiz() { + print("오늘의 퀴즈!") + let todayQuizVC = TodayQuizViewController() + todayQuizVC.modalTransitionStyle = .crossDissolve + todayQuizVC.modalPresentationStyle = .fullScreen + self.present(todayQuizVC, animated: true, completion: nil) + } + + @objc func openDoQuiz() { + print("퀴즈 풀어보기!") + + let doQuizVC = DoQuizViewController() + doQuizVC.modalTransitionStyle = .crossDissolve + doQuizVC.modalPresentationStyle = .fullScreen + self.present(doQuizVC, animated: true, completion: nil) + } + + @objc func openWrongQuiz() { + print("오답 다시 풀어보기") + + let wrongQuizVC = WrongQuizViewController() + wrongQuizVC.modalTransitionStyle = .crossDissolve + wrongQuizVC.modalPresentationStyle = .fullScreen + self.present(wrongQuizVC, animated: true, completion: nil) + } +} diff --git a/Helfy/Controller/Quiz/QuizViewController.swift b/Helfy/Controller/Quiz/QuizViewController.swift new file mode 100644 index 0000000..4b6b2f5 --- /dev/null +++ b/Helfy/Controller/Quiz/QuizViewController.swift @@ -0,0 +1,169 @@ +// +// QuestionViewController.swift +// Helfy +// +// Created by 윤성은 on 11/22/23. +// + +import UIKit + +class QuizViewController: UIViewController { + var quizView: QuizView! + var totalQuiz: Int = 0 + var currentQuizNumber: Int = 1 + var currentQuiz: QuizModel? + + var quizType = "" + var quizApiHandler: QuizAPIHandler = QuizAPIHandler() + lazy var answer: String = "" + var quizCategory: String = "" + + var convertedQuizType: QuizType? { + switch quizType { + case "MULTIPLE_CHOICE": + return .MULTIPLE_CHOICE + case "OX": + return .OX + default: + return nil + } + } + + var quizModelData: Quiz? { + didSet { + print("Hi") + } + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + + quizView = QuizView(frame: .zero, quizType: self.convertedQuizType ?? .MULTIPLE_CHOICE) + + self.view.addSubview(quizView) + + quizView.didSelectChoice = { [weak self] choice in + self?.handleChoiceSelection(choice) + } + + quizView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + quizView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + quizView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + quizView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + quizView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor) + ]) + } + + func updateUI() { + DispatchQueue.main.async { + guard let data = self.quizModelData else { return } + let currentQuiz = data[self.currentQuizNumber - 1] // 현재 퀴즈 가져오기 + print("\(currentQuiz)") + + let quizTypeString = currentQuiz.quizType + if quizTypeString.isEmpty { + print("Quiz type is empty") + return + } + guard let quizType = QuizType(rawValue: quizTypeString) else { + print("Invalid quiz type") + return + } + + self.updateQuestionNumberDisplay(current: self.currentQuizNumber, total: self.totalQuiz) + self.quizView.quizText.text = currentQuiz.question + print("\(self.quizView.quizText)") + + self.quizView.newChoice = currentQuiz.choices + self.answer = currentQuiz.answer ?? "" + self.quizView.update(quizType) + print("quizType : \(quizType)") + + // 이미지 로드 + if let imageURLString = currentQuiz.image?.imageURL, let url = URL(string: imageURLString) { + let task = URLSession.shared.dataTask(with: url) { (data, response, error) in + if let error = error { + print("Error: \(error)") + } else if let data = data { + DispatchQueue.main.async { + self.quizView.quizImage.image = UIImage(data: data) + self.quizView.updateImageLayout() // 이미지 로드 후 이미지 레이아웃 업데이트 + } + } + } + task.resume() + } else { + // 이미지가 없는 경우 + DispatchQueue.main.async { + self.quizView.quizImage.image = nil + self.quizView.updateImageLayout() // 이미지 레이아웃 업데이트 + } + } + } + } + + func setData(quizCategory: String) { + DispatchQueue.global(qos: .userInteractive).async { + //만약 첫 문제를 불러온 이후라면, API를 호출하지 않고 불러온 데이터에서 다음 문제를 로드합니다. + if self.quizModelData != nil { + self.updateUI() + } else { + self.quizApiHandler.getQuizData(type: quizCategory) { data in + self.quizModelData = data + self.totalQuiz = data.count + self.updateUI() + } + } + } + } + + func validateQuizCategory(_ category: String) -> Bool { + let validCategories = ["TODAY", "NORMAL", "WRONG"] + return validCategories.contains(category) + } + + func updateQuestionNumberDisplay(current: Int, total: Int) { + quizView.quizNumber.text = "\(current) / \(total)" + } + + func handleChoiceSelection(_ choice: String) { + guard let currentQuiz = quizModelData?[currentQuizNumber - 1] else { return } + let answerType: AnswerType = choice == currentQuiz.answer ? .correct : .wrong + + if answerType == .wrong { + print("Wrong answer, quiz id : \(currentQuiz.id)") + } else { + print("⭕️⭕️⭕️⭕️⭕️ : \(currentQuiz.id)") + } + + showResultModal(answerType: answerType, quizID: String(currentQuiz.id), currentQuiz: currentQuiz) + } + + func showResultModal(answerType: AnswerType, quizID: String, currentQuiz: QuizModel) { + let vc = CorrectOrWrongViewController(answerType: answerType, id: quizID) + vc.modalPresentationStyle = .overCurrentContext + vc.modalTransitionStyle = .crossDissolve + self.present(vc, animated: true) { + DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { + vc.dismiss(animated: true) { + if answerType == .wrong { + self.quizApiHandler.sendWrongAnswerStatus(id: String(currentQuiz.id), answerType: answerType) { _ in } + } + self.loadNextQuestion() + } + } + } + } + + func loadNextQuestion() { + if currentQuizNumber < totalQuiz { + currentQuizNumber += 1 + updateUI() + } else { + self.dismiss(animated: true, completion: nil) + } + } +} diff --git a/Helfy/Controller/Quiz/TodayQuizViewController.swift b/Helfy/Controller/Quiz/TodayQuizViewController.swift new file mode 100644 index 0000000..e3123be --- /dev/null +++ b/Helfy/Controller/Quiz/TodayQuizViewController.swift @@ -0,0 +1,31 @@ +// +// TodayQuizViewController.swift +// Helfy +// +// Created by 윤성은 on 1/4/24. +// + +import UIKit + +class TodayQuizViewController: UIViewController { + let quizVC = QuizViewController() + + override func viewDidLoad() { + super.viewDidLoad() + + addChild(quizVC) + view.addSubview(quizVC.view) + quizVC.didMove(toParent: self) + + quizVC.setData(quizCategory: "TODAY") + quizVC.quizCategory = "TODAY" + + quizVC.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + quizVC.view.topAnchor.constraint(equalTo: view.topAnchor), + quizVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + quizVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + quizVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) + } +} diff --git a/Helfy/Controller/Quiz/WrongQuizViewController.swift b/Helfy/Controller/Quiz/WrongQuizViewController.swift new file mode 100644 index 0000000..0f20177 --- /dev/null +++ b/Helfy/Controller/Quiz/WrongQuizViewController.swift @@ -0,0 +1,33 @@ +// +// WrongQuizViewController.swift +// Helfy +// +// Created by 윤성은 on 1/4/24. +// + +import UIKit + +class WrongQuizViewController: UIViewController { + let quizVC = QuizViewController() + + override func viewDidLoad() { + super.viewDidLoad() + + addChild(quizVC) + view.addSubview(quizVC.view) + quizVC.didMove(toParent: self) + + quizVC.setData(quizCategory: "WRONG") + quizVC.quizCategory = "WRONG" + + quizVC.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + quizVC.view.topAnchor.constraint(equalTo: view.topAnchor), + quizVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + quizVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + quizVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) + } + + +} diff --git a/Helfy/Controller/QuizHomeViewController.swift b/Helfy/Controller/QuizHomeViewController.swift new file mode 100644 index 0000000..188a4d6 --- /dev/null +++ b/Helfy/Controller/QuizHomeViewController.swift @@ -0,0 +1,109 @@ +// +// QuizViewController.swift +// Helfy +// +// Created by 윤성은 on 2023/10/06. + +import UIKit + +class QuizHomeViewController: UIViewController { + let quizHomeView = QuizHomeView() + var apiHandler : APIHandler = APIHandler() + var quizHomeModelData: QuizHomeModel? { + didSet { + print("Hi") + } + } + + override func viewDidLoad() { + super.viewDidLoad() + setData() + view.addSubview(quizHomeView) + + quizHomeView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + quizHomeView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + quizHomeView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + quizHomeView.topAnchor.constraint(equalTo: view.topAnchor), + quizHomeView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + + quizHomeView.todayButton.addTarget(self, action:#selector(openTodayQuiz), for:.touchUpInside) + quizHomeView.quizButton.addTarget(self, action:#selector(openDoQuiz), for:.touchUpInside) + quizHomeView.wrongButton.addTarget(self, action:#selector(openWrongQuiz), for:.touchUpInside) + } + + func setData() { + DispatchQueue.global(qos: .userInteractive).async { + + // API 통해 데이터 불러오기 + self.apiHandler.getQuizHomeData() { [self] data in + // 정의해둔 모델 객체에 할당 + self.quizHomeModelData = data + + // 데이터를 제대로 잘 받아왔다면 + guard let data = self.quizHomeModelData else { + + return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") + } + + DispatchQueue.main.async { + self.quizHomeView.idLabel.text = data.nickname + " 님" + self.quizHomeView.scoreLabel.text = "나의 점수 : " + String(data.score) + } + } + } + } + + + // 버튼 링크 연결 + @objc func openTodayQuiz() { + print("오늘의 퀴즈!") + + // TodayQuizViewController 인스턴스 생성 + let todayQuizVC = TodayQuizViewController() + + // 화면 전환 애니메이션 설정 (옵션) + todayQuizVC.modalTransitionStyle = .crossDissolve + + // 화면 전환 방식 설정 (옵션) + todayQuizVC.modalPresentationStyle = .fullScreen + + // 화면 전환 + self.present(todayQuizVC, animated: true, completion: nil) + } + + + @objc func openDoQuiz() { + print("퀴즈 풀어보기!") + + // TodayQuizViewController 인스턴스 생성 + let doQuizVC = DoQuizViewController() + + // 화면 전환 애니메이션 설정 (옵션) + doQuizVC.modalTransitionStyle = .crossDissolve + + // 화면 전환 방식 설정 (옵션) + doQuizVC.modalPresentationStyle = .fullScreen + + // 화면 전환 + self.present(doQuizVC, animated: true, completion: nil) + } + + @objc func openWrongQuiz() { + print("오답 다시 풀어보기") + + // TodayQuizViewController 인스턴스 생성 + let wrongQuizVC = WrongQuizViewController() + + // 화면 전환 애니메이션 설정 (옵션) + wrongQuizVC.modalTransitionStyle = .crossDissolve + + // 화면 전환 방식 설정 (옵션) + wrongQuizVC.modalPresentationStyle = .fullScreen + + // 화면 전환 + self.present(wrongQuizVC, animated: true, completion: nil) + } +} diff --git a/Helfy/Controller/QuizViewController.swift b/Helfy/Controller/QuizViewController.swift index 4bf0262..879c908 100644 --- a/Helfy/Controller/QuizViewController.swift +++ b/Helfy/Controller/QuizViewController.swift @@ -1,81 +1,293 @@ // -// QuizViewController.swift +// QuestionViewController.swift // Helfy // -// Created by 윤성은 on 2023/10/06. +// Created by 윤성은 on 11/22/23. +// import UIKit class QuizViewController: UIViewController { - private var quizView = QuizView() - private var rankingView = RankingView() +// lazy var quizView = QuizView(frame: .zero, quizType: self.convertedQuizType ?? .OX) + var quizView: QuizView! + // 총 문제수 + var totalQuiz: Int = 0 + // 현재 문제 번호 + var currentQuizNumber: Int = 1 - private lazy var quizButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle("퀴즈", for: .normal) - button.tintColor = UIColor.orange - button.titleLabel?.font = UIFont.systemFont(ofSize: 23) // Set font size here - button.addTarget(self, action: #selector(quizButtonTapped), for: .touchUpInside) - return button - }() + var quizType = "" + var apiHandler: APIHandler = APIHandler() + lazy var answer: String = "" + + var convertedQuizType: QuizType? { + switch quizType { + case "MULTIPLE_CHOICE": + return .MULTIPLE_CHOICE + case "OX": + return .OX + default: + return nil + } + } + + var quizModelData: Quiz? { + didSet { + print("Hi") + } + } - private lazy var rankingButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle("랭킹", for: .normal) - button.tintColor = UIColor.black - button.titleLabel?.font = UIFont.systemFont(ofSize: 23) - button.addTarget(self, action: #selector(rankingButtonTapped), for: .touchUpInside) - return button - }() - override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = UIColor.white + view.backgroundColor = .white - view.addSubview(quizView) - view.addSubview(rankingView) - - view.addSubview(quizButton) - view.addSubview(rankingButton) + quizView = QuizView(frame: .zero, quizType: self.convertedQuizType ?? .MULTIPLE_CHOICE) + + // QuizView를 뷰 계층에 추가 + self.view.addSubview(quizView) - quizButton.translatesAutoresizingMaskIntoConstraints = false - rankingButton.translatesAutoresizingMaskIntoConstraints = false + quizView.didSelectChoice = { [weak self] choice in + self?.handleChoiceSelection(choice) + } + // QuizView의 AutoLayout 설정 quizView.translatesAutoresizingMaskIntoConstraints = false - rankingView.translatesAutoresizingMaskIntoConstraints = false - - // 버튼 레이아웃 NSLayoutConstraint.activate([ - quizButton.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor, constant : 15), - quizButton.leadingAnchor.constraint(equalTo:view.leadingAnchor, constant : 20), - - rankingButton.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor, constant : 15), - rankingButton.leadingAnchor.constraint(equalTo : self.quizButton.trailingAnchor, constant : 15), + quizView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + quizView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + quizView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + quizView.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) - rankingView.isHidden = true + setData() } - // 퀴즈 버튼 눌렀을 때 동작 - @objc func quizButtonTapped() { - print("Quiz Button Tapped") - - quizView.isHidden = false - rankingView.isHidden = true - - self.quizButton.tintColor = UIColor.orange - self.rankingButton.tintColor = UIColor.black + func updateQuestionNumberDisplay(current: Int, total: Int) { + quizView.quizNumber.text = "\(current) / \(total)" + } + + func handleChoiceSelection(_ choice: String) { + let answerType: AnswerType = choice == answer ? .correct : .wrong + showResultModal(answerType: answerType) + } + + func showResultModal(answerType: AnswerType) { + let vc = CorrectOrWrongViewController(answerType: answerType) + vc.modalPresentationStyle = .overCurrentContext + vc.modalTransitionStyle = .crossDissolve + self.present(vc, animated: true) { + DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { + vc.dismiss(animated: true) { + self.loadNextQuestion() + } + } + } + } + func loadNextQuestion() { + if currentQuizNumber < totalQuiz { + setData() + currentQuizNumber += 1 + } else { + self.navigationController?.popViewController(animated: true) + } } + + func setData() { + DispatchQueue.global(qos: .userInteractive).async { + // API 통해 데이터 불러오기 + self.apiHandler.getQuizData(type: "TODAY") { data in + // 정의해둔 모델 객체에 할당 + self.quizModelData = data + + // 데이터를 제대로 잘 받아왔다면 + guard let data = self.quizModelData, !data.isEmpty else { + return print("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥") + } + + // 총 문제 수를 계산합니다. + self.totalQuiz = data.count + + DispatchQueue.main.async { [self] in + self.quizType = data[0].quizType ?? "" + print("QuizType: \(self.quizType)") // 디버깅을 위한 출력 + + self.updateQuestionNumberDisplay(current: currentQuizNumber, total: totalQuiz) - // 랭킹 버튼 눌렀을 때 동작 - @objc func rankingButtonTapped() { - print("Ranking Button Tapped") + + self.quizView.quizText.text = data[0].question + print("Quiz Text: \(self.quizView.quizText.text ?? "")") + + // 새로운 인스턴스 생성 +// let newChoice = Choices( +// choice1: data[0].choices?.choice1, +// choice2: data[0].choices?.choice2, +// choice3: data[0].choices?.choice3, +// choice4: data[0].choices?.choice4 +// ) + + self.quizView.newChoice = data[0].choices + print("newChoice: \(self.quizView.newChoice)") - quizView.isHidden = true - rankingView.isHidden = false + // 새로운 인스턴스 할당 +// self.quizView.newChoice = newChoice + +// print("Quiz Choices: \(self.quizView.newChoice)") - self.quizButton.tintColor = UIColor.black - self.rankingButton.tintColor = UIColor.orange + self.answer = data[0].answer ?? "" + self.quizView.updateMultipleChoiceUI(with: data[0].choices) + + // 이미지 로드 + if let imageURLString = data[0].image?.imageURL, let url = URL(string: imageURLString) { + let task = URLSession.shared.dataTask(with: url) { (data, response, error) in + if let error = error { + print("Error: \(error)") + } else if let data = data { + DispatchQueue.main.async { + self.quizView.quizImage.image = UIImage(data: data) + self.quizView.updateImageLayout() // 이미지 로드 후 이미지 레이아웃 업데이트 + } + } + } + + task.resume() + } + } + } + } } } + + + + +//class QuestionViewController: UIViewController { +// var questionView: QuizView! +// var choiceView: ChoiceView! +// var currentQuestionIndex = 0 +// +// override func viewDidLoad() { +// super.viewDidLoad() +// view.backgroundColor = .white +// +// let text = "지진이 났을 때, 하지말아야할 행동으로 운동장으로 뛰어간다는 맞을까요~ 틀릴까요~? 태풍이 오고 있을 때 창문에 테이프를 엑스로 붙여야할까요 세로나 가로로 붙여야할까요~?" +// let imageUrlString = "" +// let image: UIImage? = UIImage(systemName: "square.and.arrow.up") +// let data: [String: Any] = ["text": "Sample Question", "choices": ["맞다, 엑스", "틀리다, 엑스", "맞다, 세로나 가로", "틀리다, 세로나 가로"], "answerIndex": 1, "image": image] +// let type: QuestionType = .MultipleQuestion +// +// let data: [String: Any] = ["text": "Sample Question", "answer": true, "image": image] +// +// let type: QuestionType = .TrueOrFalseQuestion +// +// addChoiceView(data: data, type: type) +// +// if let image = UIImage(systemName: "square.and.arrow.up") { +// addQuestionView(text: text, image: image) +// } else { +// // 이미지 로드 중 에러가 발생한 경우 +// print("이미지 로드 에러") +// } +// +// if let imageUrl = URL(string: imageUrlString) { +// URLSession.shared.dataTask(with: imageUrl) { (data, response, error) in +// if let error = error { +// print("Error downloading image: \(error)") +// } else if let data = data { +// DispatchQueue.main.async { +// self.addQuestionView(text: text, image: UIImage(data: data)) +// } +// } +// }.resume() +// } +// } +// +// func addChoiceView(data: [String: Any], type: QuestionType) { +// // 객관식 +// if type == .MultipleQuestion { +// let multipleChoiceView = MultipleChoiceView(question: MultipleChoiceQuestion.dictionaryMultiple(data: data)) +// choiceView = multipleChoiceView +// choiceView.translatesAutoresizingMaskIntoConstraints = false +// view.addSubview(choiceView) +// NSLayoutConstraint.activate([ +// choiceView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), +// choiceView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), +// choiceView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), +// choiceView.heightAnchor.constraint(equalToConstant: 270) +// ]) +// choiceView.display() +// for button in multipleChoiceView.choiceButtons { +// button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) +// } +// } else { +// // true or false +// choiceView = TrueOrFalseQuestionView(question: TrueOrFalseQuestion.dictionaryTrueOrFalse(data: data)) +// choiceView.translatesAutoresizingMaskIntoConstraints = false +// view.addSubview(choiceView) +// NSLayoutConstraint.activate([ +// choiceView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), +// choiceView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), +// choiceView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), +// choiceView.heightAnchor.constraint(equalToConstant: 250) +// ]) +// +// choiceView.display() +// if let trueOrFalseView = choiceView as? TrueOrFalseQuestionView { +// trueOrFalseView.trueButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) +// trueOrFalseView.falseButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) +// } +// } +// } +// +// func addQuestionView(text: String, image: UIImage?) { +// questionView = QuizView(text: text, image: nil) +// questionView.translatesAutoresizingMaskIntoConstraints = false +// self.view.addSubview(questionView) +// +// // QuestionView에 대한 제약 조건 설정 +// NSLayoutConstraint.activate([ +// questionView.topAnchor.constraint(equalTo: self.view.topAnchor), +// questionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), +// questionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), +// questionView.bottomAnchor.constraint(equalTo: choiceView.topAnchor, constant: -10), +// ]) +// } +// +// @objc func buttonTapped(_ sender: UIButton) { +// // 사용자의 선택 저장 +// let userChoice = sender.tag // 각 버튼에 고유한 태그를 부여하여 구분 +// +// // 답안 체크 +// let isCorrect = checkAnswer(userChoice: userChoice) +// +// // 답안에 따른 버튼 색상 변경 +// if isCorrect == true { +// sender.backgroundColor = UIColor.systemGreen +// } else { +// sender.backgroundColor = UIColor.red +// } +// // 정답이 맞으면 다음 문제 로드 +// loadNextQuestion() +// } +// +// func checkAnswer(userChoice: Int) -> Bool { +// // MultipleChoiceQuestion 타입의 경우 +// if let multipleChoiceView = choiceView as? MultipleChoiceView { +// let correctAnswer = multipleChoiceView.question.answerIndex +// return userChoice == correctAnswer // 여기를 수정하였습니다. +// } +// // TrueOrFalseQuestion 타입의 경우 +// else if let trueOrFalseView = choiceView as? TrueOrFalseQuestionView { +// let correctAnswer = trueOrFalseView.question.answer +// return userChoice == (correctAnswer ? 1 : 0) +// } +// // 위의 경우가 아닌 경우 +// else { +// return false +// } +// } +// +// func loadNextQuestion() { +// +// } +// +//} diff --git a/Helfy/Controller/SearchViewController.swift b/Helfy/Controller/SearchViewController.swift new file mode 100644 index 0000000..4d14254 --- /dev/null +++ b/Helfy/Controller/SearchViewController.swift @@ -0,0 +1,115 @@ +// +// SearchViewController.swift +// Helfy +// +// Created by YEOMI on 2/11/24. +// +import UIKit + +class SearchViewController: UIViewController { + let apiHandler = APIHandler() + let categoryPageView = CategoryPageView() + + let searchContainerView: UIView = { + let view = UIView() + view.backgroundColor = .clear + view.layer.cornerRadius = 15.0 + view.layer.backgroundColor = CGColor(red: 249/255, green: 223/255, blue: 86/255, alpha: 1.0) + view.clipsToBounds = true + return view + }() + + let searchTextField: UITextField = { + let textField = UITextField() + textField.placeholder = "카테고리를 입력하세요" + textField.textColor = .black + textField.borderStyle = .none + return textField + }() + + let searchButtonContainer: UIView = { + let container = UIView() + container.backgroundColor = UIColor(red: 249/255, green: 164/255, blue: 86/255, alpha: 1.0) + container.layer.cornerRadius = 22.5 // 반지름을 버튼 높이의 절반으로 설정 + return container + }() + + let searchButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(systemName: "magnifyingglass"), for: .normal) + button.tintColor = .black + button.addTarget(self, action: #selector(searchButtonTapped), for: .touchUpInside) + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = UIColor.white + setupUI() + } + + func setupUI() { + view.addSubview(searchContainerView) + searchContainerView.addSubview(searchTextField) + view.addSubview(searchButtonContainer) + searchButtonContainer.addSubview(searchButton) + + searchContainerView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchContainerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + searchContainerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), + searchContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -80), + searchContainerView.heightAnchor.constraint(equalToConstant: 45) + ]) + + searchTextField.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchTextField.topAnchor.constraint(equalTo: searchContainerView.topAnchor), + searchTextField.leadingAnchor.constraint(equalTo: searchContainerView.leadingAnchor, constant: 10), + searchTextField.trailingAnchor.constraint(equalTo: searchContainerView.trailingAnchor, constant: -10), + searchTextField.bottomAnchor.constraint(equalTo: searchContainerView.bottomAnchor) + ]) + + searchButtonContainer.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchButtonContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + searchButtonContainer.leadingAnchor.constraint(equalTo: searchContainerView.trailingAnchor, constant: 10), + searchButtonContainer.widthAnchor.constraint(equalToConstant: 45), + searchButtonContainer.heightAnchor.constraint(equalToConstant: 45) + ]) + + searchButton.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchButton.centerXAnchor.constraint(equalTo: searchButtonContainer.centerXAnchor), + searchButton.centerYAnchor.constraint(equalTo: searchButtonContainer.centerYAnchor), + searchButton.widthAnchor.constraint(equalTo: searchButtonContainer.widthAnchor), + searchButton.heightAnchor.constraint(equalTo: searchButtonContainer.heightAnchor) + ]) + } + + @objc func searchButtonTapped() { + if let searchTerm = searchTextField.text, !searchTerm.isEmpty { + print("검색어: \(searchTerm)") + + // API 호출을 통해 카테고리 페이지 데이터 가져오기 + apiHandler.getCategoryPageData(category: searchTerm) { [weak self] categoryPageModel in + guard let self = self else { return } + // 카테고리 페이지 데이터를 가져왔을 때 + DispatchQueue.main.async { + // 카테고리 페이지 데이터를 설정하고 업데이트 + let categoryPageView = CategoryPageView() + categoryPageView.categoryPageData = categoryPageModel + categoryPageView.setData() + categoryPageView.backgroundColor = UIColor.white + // 모달로 카테고리 페이지 뷰를 표시 + let categoryPageViewController = CategoryPageViewController() + categoryPageViewController.view = categoryPageView + self.present(categoryPageViewController, animated: true, completion: nil) + } + } + } else { + print("카테고리를 입력하세요.") + } + } + } + diff --git a/Helfy/Info.plist b/Helfy/Info.plist index 8a22072..1d6e4d7 100644 --- a/Helfy/Info.plist +++ b/Helfy/Info.plist @@ -1,50 +1,41 @@ - - NSAppTransportSecurity - - Allow Arbitrary Loads - - - GIDClientID - 403343990842-af78k7r39uiq04h6o1p5dkh8kj1p9iof.apps.googleusercontent.com - CFBundleURLTypes - - - CFBundleURLSchemes - - com.googleusercontent.apps.403343990842-af78k7r39uiq04h6o1p5dkh8kj1p9iof - - - - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - com.googleusercontent.apps.403343990842-af78k7r39uiq04h6o1p5dkh8kj1p9iof - - - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.403343990842-af78k7r39uiq04h6o1p5dkh8kj1p9iof + + + + GIDClientID + 403343990842-af78k7r39uiq04h6o1p5dkh8kj1p9iof.apps.googleusercontent.com + NSAppTransportSecurity + + Allow Arbitrary Loads + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + diff --git a/Helfy/Model/CategoryModel.swift b/Helfy/Model/CategoryModel.swift new file mode 100644 index 0000000..0e9cfea --- /dev/null +++ b/Helfy/Model/CategoryModel.swift @@ -0,0 +1,43 @@ +// +// CategoryModel.swift +// Helfy +// +// Created by 윤성은 on 2/18/24. +// + +import Foundation + +// MARK: - Welcome +struct CategoryModel: Codable { + let flood, volcanicEruption, landslide, typhoon: String + let heavySnow, lightning, strongWind, yellowDust: String + let drought, spacePropagationDisaster, tidalWave, theFallOfNaturalSpaceObjects: String + let heavyRain, flooding, heatWave, greenTide: String + let coldWave, tsunami, risingSeaLevel, earthquake: String + let windAndWaves, redTide: String + + enum CodingKeys: String, CodingKey { + case flood = "FLOOD" + case volcanicEruption = "VOLCANIC_ERUPTION" + case landslide = "LANDSLIDE" + case typhoon = "TYPHOON" + case heavySnow = "HEAVY_SNOW" + case lightning = "LIGHTNING" + case strongWind = "STRONG_WIND" + case yellowDust = "YELLOW_DUST" + case drought = "DROUGHT" + case spacePropagationDisaster = "SPACE_PROPAGATION_DISASTER" + case tidalWave = "TIDAL_WAVE" + case theFallOfNaturalSpaceObjects = "THE_FALL_OF_NATURAL_SPACE_OBJECTS" + case heavyRain = "HEAVY_RAIN" + case flooding = "FLOODING" + case heatWave = "HEAT_WAVE" + case greenTide = "GREEN_TIDE" + case coldWave = "COLD_WAVE" + case tsunami = "TSUNAMI" + case risingSeaLevel = "RISING_SEA_LEVEL" + case earthquake = "EARTHQUAKE" + case windAndWaves = "WIND_AND_WAVES" + case redTide = "RED_TIDE" + } +} diff --git a/Helfy/Model/CategoryPageModel.swift b/Helfy/Model/CategoryPageModel.swift new file mode 100644 index 0000000..ee99f93 --- /dev/null +++ b/Helfy/Model/CategoryPageModel.swift @@ -0,0 +1,33 @@ +// +// CategoryPageModel.swift +// Helfy +// +// Created by YEOMI on 12/1/23. +// + +import Foundation + +// MARK: - Helfy +struct CategoryPageModel: Codable { + let id: Int + let category, content, newsURL, youtubeURL: String + let image: Image + + enum CodingKeys: String, CodingKey { + case id, category, content + case newsURL = "news_url" + case youtubeURL = "youtube_url" + case image + } +} + +// MARK: - Image +struct Image: Codable { + let id: Int + let imageURL: String + + enum CodingKeys: String, CodingKey { + case id + case imageURL = "imageUrl" + } +} diff --git a/Helfy/Model/MainModel.swift b/Helfy/Model/MainModel.swift new file mode 100644 index 0000000..7349adf --- /dev/null +++ b/Helfy/Model/MainModel.swift @@ -0,0 +1,27 @@ +// +// MainModel.swift +// Helfy +// +// Created by 윤성은 on 2/5/24. +// + +import Foundation + +// MARK: - Welcome +struct MainModel: Codable { + let userInfo: IdInfo + let weatherInfo: WeatherInfo +} + +// MARK: - UserInfo +struct IdInfo: Codable { + let id: Int + let nickname: String +} + +// MARK: - WeatherInfo +struct WeatherInfo: Codable { + let weatherCode: String + let temp: Double + let humidity: Int +} diff --git a/Helfy/Model/MypageModel.swift b/Helfy/Model/MypageModel.swift index 916c6d0..5eb76ca 100644 --- a/Helfy/Model/MypageModel.swift +++ b/Helfy/Model/MypageModel.swift @@ -5,32 +5,20 @@ // Created by 윤성은 on 11/8/23. // -import UIKit +import Foundation -// User 모델 클래스 -class User2 { - var nickname: String - var location: String - - init(nickname: String, location: String) { - self.nickname = nickname - self.location = location - } +// MARK: - Welcome +struct MypageModel: Codable { + let userInfo: UserInfo + let rankInfo: RankInfo } -class MypageModel { - var user: User2 - - init(user: User2) { - self.user = user - } - - // myPageView를 사용하여 UI를 업데이트하는 메서드 - func updateUI() { - let myPageView = MypageView() - myPageView.nicknameLabel.text = user.nickname - myPageView.locationLabel.text = user.location - } +// MARK: - RankInfo +struct RankInfo: Codable { + let rank, score: Int } - +// MARK: - UserInfo +struct UserInfo: Codable { + let region, nickname: String +} diff --git a/Helfy/Model/QuestionModel.swift b/Helfy/Model/QuestionTestModel.swift similarity index 84% rename from Helfy/Model/QuestionModel.swift rename to Helfy/Model/QuestionTestModel.swift index a5c38c5..c47b4a2 100644 --- a/Helfy/Model/QuestionModel.swift +++ b/Helfy/Model/QuestionTestModel.swift @@ -7,7 +7,7 @@ import UIKit -class QuestionModel { +class QuestionTestModel { var text: String var image: UIImage? @@ -17,7 +17,7 @@ class QuestionModel { } } -class MultipleChoiceQuestion: QuestionModel { +class MultipleChoiceQuiz: QuestionTestModel { var choices: [String] var answerIndex: Int @@ -27,16 +27,16 @@ class MultipleChoiceQuestion: QuestionModel { super.init(text: text, image: image) } - static func dictionaryMultiple(data: [String: Any]) -> MultipleChoiceQuestion { + static func dictionaryMultiple(data: [String: Any]) -> MultipleChoiceQuiz { let text = data["text"] as! String let choices = data["choices"] as! [String] let answerIndex = data["answerIndex"] as! Int let image = data["image"] as? UIImage - return MultipleChoiceQuestion(text: text, choices: choices, answerIndex: answerIndex, image: image) + return MultipleChoiceQuiz(text: text, choices: choices, answerIndex: answerIndex, image: image) } } -class TrueOrFalseQuestion: QuestionModel { +class TrueOrFalseQuestion: QuestionTestModel { var answer: Bool init(text: String, answer: Bool, image: UIImage? = nil) { diff --git a/Helfy/Model/QuizHomeModel.swift b/Helfy/Model/QuizHomeModel.swift new file mode 100644 index 0000000..1c16115 --- /dev/null +++ b/Helfy/Model/QuizHomeModel.swift @@ -0,0 +1,13 @@ +// +// QuizHomeModel.swift +// Helfy +// +// Created by 윤성은 on 1/7/24. +// + +import Foundation + +struct QuizHomeModel: Codable { + let nickname: String + let score: Int +} diff --git a/Helfy/Model/QuizModel.swift b/Helfy/Model/QuizModel.swift new file mode 100644 index 0000000..be99656 --- /dev/null +++ b/Helfy/Model/QuizModel.swift @@ -0,0 +1,30 @@ +// +// QuizModel.swift +// Helfy +// +// Created by 윤성은 on 12/27/23. +// + +import Foundation + +// MARK: - WelcomeElement +struct QuizModel: Codable { + let id: Int + let question, answer: String + let choices: [String: String] + let image: Image? + let quizType: String +} + +// MARK: - Image +struct Image: Codable { + let id: Int + let imageURL: String + + enum CodingKeys: String, CodingKey { + case id + case imageURL = "imageUrl" + } +} + +typealias Quiz = [QuizModel] diff --git a/Helfy/Model/QuizeModel.swift b/Helfy/Model/QuizeModel.swift deleted file mode 100644 index 151cbf5..0000000 --- a/Helfy/Model/QuizeModel.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// QuizeModel.swift -// Helfy -// -// Created by 김하은 on 2023/10/11. -// - -import UIKit - -struct QuizeModel { - var name: String -} diff --git a/Helfy/MyPageAPIHandler.swift b/Helfy/MyPageAPIHandler.swift new file mode 100644 index 0000000..b6768f7 --- /dev/null +++ b/Helfy/MyPageAPIHandler.swift @@ -0,0 +1,90 @@ +// +// MyPageAPIHandler.swift +// Helfy +// +// Created by 윤성은 on 1/29/24. +// + +import Foundation + +class MyPageAPIHandler { + + let token = UserDefaults.standard.string(forKey: "GoogleToken") ?? "" + + func getMyPageData(completion: @escaping (MypageModel) -> ()) { + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/user") else { + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let myPageParsedData = try JSONDecoder().decode(MypageModel.self, from: data) + completion(myPageParsedData) + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } + + func updateMyPageData(nickname: String?, region: String?, completion: @escaping (Bool) -> Void) { + let url = URL(string: "https://helfy-server.duckdns.org/api/v1/user")! + var request = URLRequest(url: url) + request.httpMethod = "PATCH" + request.setValue("application/json;charset=UTF-8", forHTTPHeaderField: "Content-Type") + request.setValue("application/json;charset=UTF-8", forHTTPHeaderField: "accept") + request.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + + var body: [String: Any] = [:] + if let nickname = nickname { + body["nickname"] = nickname + } + if let region = region { + body["region"] = region + } + request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + if let error = error { + print("Error: \(error)") + completion(false) // 콜백 추가 + } else if let httpResponse = response as? HTTPURLResponse { + print("Status Code: \(httpResponse.statusCode)") + + if httpResponse.statusCode == 200 { + completion(true) // 콜백 추가 + } else { + completion(false) // 콜백 추가 + } + + if let data = data { + do { + let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + let nickname = json?["nickname"] as? String + let region = json?["region"] as? String + } catch { + print("Error: \(error)") + } + } + } + } + task.resume() + + } +} diff --git a/Helfy/QuizAPIHandler.swift b/Helfy/QuizAPIHandler.swift new file mode 100644 index 0000000..ded0d50 --- /dev/null +++ b/Helfy/QuizAPIHandler.swift @@ -0,0 +1,132 @@ +// +// APIHandler.swift +// Helfy +// +// Created by 윤성은 on 1/3/24. +// + +import Foundation + +class QuizAPIHandler { + + var token = UserDefaults.standard.string(forKey: "GoogleToken") ?? "" + + func getQuizHomeData(completion: @escaping (QuizHomeModel) -> ()) { + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/quiz/users") else { + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let quizHomeParsedData = try JSONDecoder().decode(QuizHomeModel.self, from: data) + completion(quizHomeParsedData) + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { print("Status code: \(response.statusCode)") } + } + }.resume() + } + + func getQuizData(type: String, completion: @escaping (Quiz) -> ()) { + var apiUrl: String + switch type { + case "TODAY": + apiUrl = "https://helfy-server.duckdns.org/api/v1/quiz?type=TODAY" + case "NORMAL": + apiUrl = "https://helfy-server.duckdns.org/api/v1/quiz?type=NORMAL" + case "WRONG": + apiUrl = "https://helfy-server.duckdns.org/api/v1/quiz/users/wrong" + default: + print("Invalid quiz category") + return + } + + guard let url = URL(string: apiUrl) else { + print("Invalid URL") + return + } + + print("token 값 : \(self.token)") + + var requestURL = URLRequest(url: url) + requestURL.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + print(requestURL,"requestURL") + + + // 2. 데이터를 받아오기 위한 URLSession의 dataTask를 생성 + URLSession.shared.dataTask(with: requestURL) { data, response, error in + // 3. 에러 처리, 데이터 및 리스폰스 확인, 디코딩 등등 출동 + guard error == nil else { + print(error?.localizedDescription ?? "") + return + } + + if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 { + do { + let quizParsedData = try JSONDecoder().decode(Quiz.self, from: data) + completion(quizParsedData) + print("quizParsedData: \(quizParsedData)") + } catch { + print(error.localizedDescription) + } + } else { + if let response = response as? HTTPURLResponse { + print("Status code: \(response.statusCode)") + } + + } + }.resume() + } + + func sendWrongAnswerStatus(id: String, answerType: AnswerType, completion: @escaping (Quiz) -> ()) { + if answerType == .wrong { + // URL 준비 + guard let url = URL(string: "https://helfy-server.duckdns.org/api/v1/quiz/users/\(id)/result") else { return } + print("🔴🔴🔴ID : \(id)") + + // PUT 요청 생성 + var request = URLRequest(url: url) + request.httpMethod = "PUT" + request.setValue("application/json;charset=UTF-8", forHTTPHeaderField: "Content-Type") + request.setValue("application/json;charset=UTF-8", forHTTPHeaderField: "accept") + request.setValue("Bearer \(self.token)", forHTTPHeaderField: "Authorization") + + // 필요한 경우 httpBody를 설정하여 요청에 데이터를 포함시킬 수 있습니다. + let parameters: [String: Any] = ["quizStatus": "WRONG"] + request.httpBody = try? JSONSerialization.data(withJSONObject: parameters) + + // 요청 발행 + let task = URLSession.shared.dataTask(with: request) { data, response, error in + if let error = error { + print("Error: \(error)") + } else if let data = data { + // 응답 데이터 처리 + let str = String(data: data, encoding: .utf8) + print("Received data:\n\(str ?? "")") + } + + if let httpResponse = response as? HTTPURLResponse { + print("Response status code: \(httpResponse.statusCode)") + } + } + + task.resume() + } + } +} diff --git a/Helfy/View/BannerView.swift b/Helfy/View/BannerView.swift new file mode 100644 index 0000000..7a98970 --- /dev/null +++ b/Helfy/View/BannerView.swift @@ -0,0 +1,123 @@ +// +// BannerView.swift +// Helfy +// +// Created by YEOMI on 2/10/24. +// +import UIKit + +class BannerView: UIView, UIScrollViewDelegate { + private let scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.isPagingEnabled = true + scrollView.showsHorizontalScrollIndicator = false + scrollView.bounces = false + scrollView.alwaysBounceVertical = false + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.clipsToBounds = true // 이 부분을 추가합니다. + return scrollView + }() + + func getScrollViewHeight() -> CGFloat { + return scrollView.frame.size.height + } + + private let pageControl: UIPageControl = { + let pageControl = UIPageControl() + pageControl.pageIndicatorTintColor = .lightGray // 페이지 인디케이터의 색상을 설정합니다. + pageControl.currentPageIndicatorTintColor = .black + pageControl.translatesAutoresizingMaskIntoConstraints = false + return pageControl + }() + + var banners: [(image: UIImage, text: String)] = [] { + didSet { + pageControl.numberOfPages = banners.count + pageControl.currentPage = 0 + setupBanners() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + scrollView.delegate = self + setupView() + bringSubviewToFront(pageControl) + + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + scrollView.delegate = self + setupView() + bringSubviewToFront(pageControl) + + } + + private func setupView() { + addSubview(scrollView) + addSubview(pageControl) + self.layer.cornerRadius = 20 + self.clipsToBounds = true + let backgroundColor = UIColor(red: 249/255, green: 223/255, blue: 86/255, alpha: 1.0) + self.backgroundColor = backgroundColor + + + NSLayoutConstraint.activate([ + scrollView.topAnchor.constraint(equalTo: topAnchor), + scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: pageControl.topAnchor), + // 스크롤뷰의 하단을 페이지 컨트롤의 상단에 위치시킵니다. + + pageControl.leadingAnchor.constraint(equalTo: leadingAnchor), + pageControl.trailingAnchor.constraint(equalTo: trailingAnchor), + pageControl.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10), + pageControl.heightAnchor.constraint(equalToConstant: 50) // 페이지 컨트롤의 높이를 설정합니다. + ]) + } + + + private func setupBanners() { + for i in 0.. String { + return contentView.text + } +} + diff --git a/Helfy/View/CategoryView.swift b/Helfy/View/CategoryView.swift index d2db1c6..9a63ee1 100644 --- a/Helfy/View/CategoryView.swift +++ b/Helfy/View/CategoryView.swift @@ -8,108 +8,92 @@ import UIKit -class CategoryButton: UIView { - let myImageView = UIImageView() - let myTitleLabel = UILabel() +class CategoryCell: UICollectionViewCell { + + let categoryView: CategoryView = { + let cv = CategoryView() + cv.translatesAutoresizingMaskIntoConstraints = false + return cv + }() + + override func prepareForReuse() { + super.prepareForReuse() - init(image: UIImage?, title: String) { - super.init(frame: .zero) - - myImageView.image = image - myTitleLabel.text = title - myTitleLabel.font = UIFont.systemFont(ofSize: 12) - myTitleLabel.textAlignment = .center - - self.addSubview(myImageView) - self.addSubview(myTitleLabel) - - // Set content mode of image view to scale aspect fit. - myImageView.contentMode = .scaleAspectFit + categoryView.buttonLabel.text = nil + categoryView.buttonImageView.image = nil + } + + override init(frame: CGRect) { + super.init(frame: frame) - // Image 설정 - myImageView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - myImageView.widthAnchor.constraint(equalToConstant: 90), - myImageView.heightAnchor.constraint(equalToConstant: 60), - myImageView.topAnchor.constraint(equalTo:self.topAnchor), - myImageView.centerXAnchor.constraint(equalTo:self.centerXAnchor) - ]) + contentView.addSubview(categoryView) - // TitleLabel 설정 - myTitleLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ - myTitleLabel.topAnchor.constraint(equalTo:myImageView.bottomAnchor, constant: 5), - myTitleLabel.leadingAnchor.constraint(equalTo:self.leadingAnchor), - myTitleLabel.trailingAnchor.constraint(equalTo:self.trailingAnchor), - myTitleLabel.bottomAnchor.constraint(lessThanOrEqualTo:self.bottomAnchor) + categoryView.topAnchor.constraint(equalTo: contentView.topAnchor), + categoryView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + categoryView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + categoryView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) ]) - - let tapGesture = UITapGestureRecognizer(target: self, action:#selector(buttonTapped)) - self.addGestureRecognizer(tapGesture) } - @objc func buttonTapped() { - print("Button was tapped!") - } - - required init?(coder aDecoder:NSCoder) { + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } - -class CategoryView : UIView { - override init(frame:CGRect) { - super.init(frame:frame) +class CategoryView: UIView { + + var buttonAction: (() -> Void)? + + @objc func handleButtonPressed() { + buttonAction?() + print("Button was pressed!") + + } + + let buttonImageView: UIImageView = { + let iv = UIImageView() + iv.contentMode = .scaleAspectFit + iv.translatesAutoresizingMaskIntoConstraints = false + return iv + }() + + let buttonLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.font = UIFont.boldSystemFont(ofSize: 17) + label.numberOfLines = 0 + label.lineBreakMode = .byWordWrapping + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(buttonImageView) + addSubview(buttonLabel) + + let tapGestureRecognizer1 = UITapGestureRecognizer(target: self, action: #selector(handleButtonPressed)) + let tapGestureRecognizer2 = UITapGestureRecognizer(target: self, action: #selector(handleButtonPressed)) + buttonImageView.addGestureRecognizer(tapGestureRecognizer1) + buttonLabel.addGestureRecognizer(tapGestureRecognizer2) + buttonImageView.isUserInteractionEnabled = true + buttonLabel.isUserInteractionEnabled = true - let buttonTitles = ["침수", "태풍", "호우","낙뢰", - "강풍", "풍랑", "대설", "한파", - "폭염", "황사", "지진", "해일", - "지진해일", "화산폭발", "가뭄","홍수", - "해수면상승", "산사태","자연우주물체추락", "우주전파재난", - "녹조", "적조"] - let buttonImages = [UIImage(named:"침수"), UIImage(named:"태풍"), UIImage(named: "호우"), - UIImage(named:"낙뢰"), UIImage(named:"강풍"), UIImage(named: "풍랑"), - UIImage(named:"대설"), UIImage(named:"한파"), UIImage(named:"폭염"), - UIImage(named:"황사"), UIImage(named:"지진"), UIImage(named:"해일"), - UIImage(named:"지진해일"), UIImage(named:"화산폭발"), UIImage(named:"가뭄"), - UIImage(named:"홍수"), UIImage(named:"해수면상승"), UIImage(named:"산사태"), - UIImage(named:"자연우주물체추락"), UIImage(named:"우주전파재난"), UIImage(named:"녹조"), UIImage(named:"적조") ] - - let stackView = UIStackView() - stackView.axis = .vertical - stackView.distribution = .fillEqually - stackView.spacing = 5 - - for i in stride(from:0, to:buttonTitles.count, by:4) { - let hStack = UIStackView() - hStack.axis = .horizontal - hStack.distribution = .fillEqually - hStack.spacing = 5 - - for j in i..> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) + case 6: // RGB (24-bit) + (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) + case 8: // ARGB (32-bit) + (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) + default: + (a, r, g, b) = (255, 0, 0, 0) + } + self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) + } +} + diff --git a/Helfy/View/MypageView.swift b/Helfy/View/MypageView.swift index dd79692..312eb91 100644 --- a/Helfy/View/MypageView.swift +++ b/Helfy/View/MypageView.swift @@ -12,79 +12,143 @@ class MypageView: UIView { // 프로필 이미지 let profileImageView: UIImageView = { let imageView = UIImageView() - imageView.frame = CGRect(x: 0, y: 0, width: 200, height: 200) imageView.contentMode = .scaleAspectFill - imageView.image = UIImage(systemName: "person.circle.fill") + imageView.image = UIImage(systemName: "person.crop.square.fill")?.withTintColor(UIColor(hex: "#F9DF56"), renderingMode: .alwaysOriginal) imageView.isUserInteractionEnabled = true - imageView.layer.cornerRadius = 100 + imageView.layer.cornerRadius = 50 imageView.clipsToBounds = true + imageView.translatesAutoresizingMaskIntoConstraints = false return imageView }() - - // 닉네임 + + let smallIconImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.image = UIImage(systemName: "camera.circle.fill")?.withTintColor(.gray, renderingMode: .alwaysOriginal) + imageView.backgroundColor = UIColor.white + imageView.layer.cornerRadius = 25 + imageView.layer.masksToBounds = true + imageView.translatesAutoresizingMaskIntoConstraints = false + return imageView + }() + let nicknameLabel: UILabel = { let label = UILabel() label.textColor = .black - label.font = UIFont.boldSystemFont(ofSize: 27) + label.font = UIFont.boldSystemFont(ofSize: 30) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = false + label.numberOfLines = 0 + label.isUserInteractionEnabled = true + label.minimumScaleFactor = 0.1 + label.translatesAutoresizingMaskIntoConstraints = false return label }() - - // 지역 - let locationLabel: UILabel = { + + let regionLabel: UILabel = { let label = UILabel() label.textColor = .black - label.font = UIFont.boldSystemFont(ofSize: 23) + label.font = UIFont.boldSystemFont(ofSize: 25) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = false + label.isUserInteractionEnabled = true + label.minimumScaleFactor = 0.1 + label.translatesAutoresizingMaskIntoConstraints = false return label }() + + lazy var idStackView: UIStackView = { + let sv = UIStackView(arrangedSubviews: [nicknameLabel, regionLabel]) + sv.axis = .vertical + sv.spacing = 15 + sv.distribution = .fill + sv.translatesAutoresizingMaskIntoConstraints = false + return sv + }() - // 닉네임, 지역 변경 버튼 - let changeNicknameButton: UIButton = createButton(withTitle: "닉네임 변경") - let changeLocationButton: UIButton = createButton(withTitle: "지역 변경") + let separatorView: UIView = { + let view = UIView() + view.backgroundColor = .gray + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() - static func createButton(withTitle title: String) -> UIButton { - let button = UIButton(type: .system) - - button.setTitle(title, for: .normal) - button.setTitleColor(UIColor.black, for:.normal) - button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 25) - button.backgroundColor = UIColor(hexString:"#F9DF56") - button.layer.cornerRadius = 20 - - button.heightAnchor.constraint(equalToConstant: 70).isActive = true - button.widthAnchor.constraint(equalToConstant: 150).isActive = true - - return button - } + let rankTextLabel: UILabel = { + let label = UILabel() + label.text = "순위" + label.textColor = .darkGray + label.font = UIFont.systemFont(ofSize: 22) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.numberOfLines = 0 + label.isUserInteractionEnabled = true + label.minimumScaleFactor = 0.1 + return label + }() - lazy var stackView: UIStackView = { - let stackButton = UIStackView() - stackButton.axis = .horizontal - stackButton.alignment = .center - stackButton.distribution = .fillEqually - stackButton.spacing = 20 - - return stackButton + let rankLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.boldSystemFont(ofSize: 27) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.numberOfLines = 0 + label.isUserInteractionEnabled = true // 사용자 상호작용 활성화 + label.minimumScaleFactor = 0.1 + label.translatesAutoresizingMaskIntoConstraints = false + return label }() - // 나중에 채울 버튼들 - let tableView: UITableView = { - let tableView = UITableView() - tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ButtonCell") - tableView.separatorStyle = .singleLine - tableView.separatorColor = UIColor.black - - return tableView + lazy var rankStackView: UIStackView = { + let sv = UIStackView(arrangedSubviews: [rankTextLabel, rankLabel]) + sv.axis = .vertical + sv.spacing = 10 + sv.distribution = .fillEqually + sv.translatesAutoresizingMaskIntoConstraints = false + return sv + }() + + let scoreTextLabel: UILabel = { + let label = UILabel() + label.text = "점수" + label.textColor = .darkGray + label.font = UIFont.systemFont(ofSize: 22) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.numberOfLines = 0 + label.isUserInteractionEnabled = true // 사용자 상호작용 활성화 + label.minimumScaleFactor = 0.1 + return label + }() + + let scoreLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.boldSystemFont(ofSize: 27) + label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.numberOfLines = 0 + label.isUserInteractionEnabled = true // 사용자 상호작용 활성화 + label.minimumScaleFactor = 0.1 + label.translatesAutoresizingMaskIntoConstraints = false + return label }() - let buttons: [String] = ["뭐1", "뭐2", "뭐3", "뭐4", "문의"] + lazy var scoreStackView: UIStackView = { + let sv = UIStackView(arrangedSubviews: [scoreTextLabel, scoreLabel]) + sv.axis = .vertical + sv.spacing = 10 + sv.distribution = .fillEqually + return sv + }() - // 로그아웃 버튼 - let logoutButton: UIButton = { - let button = UIButton() - button.setTitle("로그아웃", for: .normal) - button.setTitleColor(UIColor.black, for: .normal) - button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20) - return button + lazy var containerStackView: UIStackView = { + let container = UIStackView(arrangedSubviews: [rankStackView, scoreStackView]) + container.axis = .horizontal + container.distribution = .fillEqually + container.spacing = 15 + container.translatesAutoresizingMaskIntoConstraints = false + return container }() override init(frame: CGRect) { @@ -98,58 +162,54 @@ class MypageView: UIView { private func setupUI() { addSubview(profileImageView) - addSubview(nicknameLabel) - addSubview(locationLabel) - addSubview(stackView) - addSubview(tableView) - addSubview(logoutButton) - - stackView.addArrangedSubview(changeNicknameButton) - stackView.addArrangedSubview(changeLocationButton) - - profileImageView.translatesAutoresizingMaskIntoConstraints = false - nicknameLabel.translatesAutoresizingMaskIntoConstraints = false - locationLabel.translatesAutoresizingMaskIntoConstraints = false - stackView.translatesAutoresizingMaskIntoConstraints = false - tableView.translatesAutoresizingMaskIntoConstraints = false - logoutButton.translatesAutoresizingMaskIntoConstraints = false - - let cellHeight: CGFloat = 44 + addSubview(smallIconImageView) + addSubview(idStackView) + addSubview(separatorView) + addSubview(containerStackView) NSLayoutConstraint.activate([ profileImageView.topAnchor.constraint(equalTo: topAnchor, constant: 110), - profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 35), - profileImageView.widthAnchor.constraint(equalToConstant: 200), - profileImageView.heightAnchor.constraint(equalToConstant: 200), + profileImageView.widthAnchor.constraint(equalToConstant: 180), + profileImageView.heightAnchor.constraint(equalToConstant: 180), + profileImageView.centerXAnchor.constraint(equalTo: centerXAnchor), - nicknameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 50), - nicknameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor), + smallIconImageView.bottomAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 5), // 수정된 부분 + smallIconImageView.trailingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 10), // 수정된 부분 + smallIconImageView.widthAnchor.constraint(equalToConstant: 50), + smallIconImageView.heightAnchor.constraint(equalToConstant: 50), - locationLabel.topAnchor.constraint(equalTo: nicknameLabel.bottomAnchor, constant: 15), - locationLabel.centerXAnchor.constraint(equalTo: nicknameLabel.centerXAnchor), - - stackView.centerXAnchor.constraint(equalTo: centerXAnchor), - stackView.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 30), - - tableView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 20), - tableView.centerXAnchor.constraint(equalTo: centerXAnchor), - tableView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), - tableView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), - tableView.heightAnchor.constraint(equalToConstant: (cellHeight + 8) * CGFloat(buttons.count)), + idStackView.centerXAnchor.constraint(equalTo: centerXAnchor), + idStackView.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 50), + idStackView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.8), + + separatorView.topAnchor.constraint(equalTo: idStackView.bottomAnchor, constant: 40), + separatorView.centerXAnchor.constraint(equalTo: centerXAnchor), + separatorView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.8), + separatorView.heightAnchor.constraint(equalToConstant: 1), - logoutButton.centerXAnchor.constraint(equalTo: centerXAnchor), - logoutButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 35) + containerStackView.centerXAnchor.constraint(equalTo: centerXAnchor), + containerStackView.topAnchor.constraint(equalTo: separatorView.bottomAnchor, constant: 40), + containerStackView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.8), ]) } - - // User 정보를 기반으로 UI 업데이트 - func updateUserUI(user: User2) { - nicknameLabel.text = user.nickname - locationLabel.text = user.location - } - - // 프로필 이미지 업데이트 - func updateProfileImage(_ image: UIImage) { - profileImageView.image = image +} + +extension UIColor { + convenience init(hex: String) { + let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) + var int = UInt64() + Scanner(string: hex).scanHexInt64(&int) + let a, r, g, b: UInt64 + switch hex.count { + case 3: // RGB (12-bit) + (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) + case 6: // RGB (24-bit) + (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) + case 8: // ARGB (32-bit) + (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) + default: + (a, r, g, b) = (255, 0, 0, 0) + } + self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) } } diff --git a/Helfy/View/Qtest.swift b/Helfy/View/Qtest.swift new file mode 100644 index 0000000..f755bf8 --- /dev/null +++ b/Helfy/View/Qtest.swift @@ -0,0 +1,152 @@ +// +// Qtest.swift +// Helfy +// +// Created by 윤성은 on 1/17/24. +// + +//import UIKit +// +//enum QuizType { +// case MULTIPLE_CHOICE +// case OX +//} +// +//class QuizView: UIView { +// var quizType: QuizType +// var newChoice = Choices(additionalProp1: "", additionalProp2: "", additionalProp3: "") +// var arr: [String] = [] +// +// var choiceButtons: [UIButton] = [] +// var trueButton: UIButton = UIButton() +// var falseButton: UIButton = UIButton() +// +// init(frame: CGRect, quizType: QuizType) { +// self.quizType = quizType +// super.init(frame: frame) +// setLayout() +// setUI() +// } +// +// required init?(coder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +// +// // 텍스트 +// let quizText: UILabel = { +// let label = UILabel() +// label.translatesAutoresizingMaskIntoConstraints = false +// label.numberOfLines = 0 +// label.font = .boldSystemFont(ofSize: 22) +// label.textAlignment = .center +// return label +// }() +// +// // 이미지 +// let quizImage: UIImageView = { +// let image: UIImageView = UIImageView() +// image.translatesAutoresizingMaskIntoConstraints = false +// image.contentMode = .scaleAspectFit +// return image +// }() +// +// func setLayout() { +// self.addSubview(quizImage) +// self.addSubview(quizText) +// +// quizImage.translatesAutoresizingMaskIntoConstraints = false +// quizText.translatesAutoresizingMaskIntoConstraints = false +// +// NSLayoutConstraint.activate([ +// quizText.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 50), +// quizText.centerXAnchor.constraint(equalTo: self.centerXAnchor), +// +// quizImage.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), +// quizImage.centerXAnchor.constraint(equalTo: self.centerXAnchor), +// ]) +// } +// +// func setUI() { +// switch quizType { +// case .MULTIPLE_CHOICE: +// var choiceButtons: [UIButton] = [] +// +// let buttonStackView: UIStackView = { +// let buttonStack = UIStackView() +// buttonStack.axis = .vertical +// buttonStack.distribution = .fillEqually +// buttonStack.spacing = 10 +// buttonStack.translatesAutoresizingMaskIntoConstraints = false +// +// return buttonStack +// }() +// +// self.addSubview(buttonStackView) +// +// // Use newChoice data for buttons +// let testChoices = ["1", "2", "3", "4"] +// +// // Create buttons based on testChoices +// for choice in testChoices { +// let button = UIButton() +// button.setTitle(choice, for: .normal) +// button.setTitleColor(.black, for: .normal) +// button.titleLabel?.font = UIFont.systemFont(ofSize: 20) +// button.layer.cornerRadius = 20 +// button.backgroundColor = UIColor(hexString: "#F9DF56") +// +// buttonStackView.addArrangedSubview(button) +// choiceButtons.append(button) +// } +// +// buttonStackView.translatesAutoresizingMaskIntoConstraints = false +// NSLayoutConstraint.activate([ +// buttonStackView.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), +// buttonStackView.centerXAnchor.constraint(equalTo: self.centerXAnchor), +// buttonStackView.centerYAnchor.constraint(equalTo: self.centerYAnchor), +// buttonStackView.widthAnchor.constraint(equalToConstant: 350), +// buttonStackView.heightAnchor.constraint(equalToConstant: 220) +// ]) +// +// break +// +// case .OX: +// // O/X 선택지 버튼 생성 +// trueButton = UIButton() +// trueButton.setTitle("O", for: .normal) +// trueButton.titleLabel?.font = .systemFont(ofSize: 50) +// trueButton.backgroundColor = UIColor(hexString: "#F9DF56") +// trueButton.layer.cornerRadius = 20 +// trueButton.tag = 1 +// +// falseButton = UIButton() +// falseButton.setTitle("X", for: .normal) +// falseButton.titleLabel?.font = .systemFont(ofSize: 50) +// falseButton.backgroundColor = UIColor(hexString: "#F9A456") +// falseButton.layer.cornerRadius = 20 +// falseButton.tag = 0 +// +// self.addSubview(trueButton) +// self.addSubview(falseButton) +// +// // AutoLayout 설정 +// trueButton.translatesAutoresizingMaskIntoConstraints = false +// falseButton.translatesAutoresizingMaskIntoConstraints = false +// +// NSLayoutConstraint.activate([ +// trueButton.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), +// trueButton.heightAnchor.constraint(equalToConstant: 200), +// trueButton.widthAnchor.constraint(equalToConstant: 130), +// trueButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), +// trueButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 50), +// +// falseButton.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), +// falseButton.leadingAnchor.constraint(equalTo: trueButton.trailingAnchor, constant: 30), +// falseButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), +// falseButton.heightAnchor.constraint(equalToConstant: 200), +// falseButton.widthAnchor.constraint(equalToConstant: 130) +// ]) +// break +// } +// } +//} diff --git a/Helfy/View/Question/ChoiceView.swift b/Helfy/View/Question/ChoiceView.swift deleted file mode 100644 index 4f22af4..0000000 --- a/Helfy/View/Question/ChoiceView.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// ChoiceView.swift -// Helfy -// -// Created by 윤성은 on 11/23/23. -// - -import UIKit - -class ChoiceView: UIView { - var buttons: [UIButton] = [] - - func display() {} -} diff --git a/Helfy/View/Question/MultipleChoiceView.swift b/Helfy/View/Question/MultipleChoiceView.swift deleted file mode 100644 index fd37abf..0000000 --- a/Helfy/View/Question/MultipleChoiceView.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// MultipleChoiceView.swift -// Helfy -// -// Created by 윤성은 on 11/23/23. -// -// 객관식 - -import UIKit - -class MultipleChoiceView: ChoiceView { - var choiceButtons: [UIButton] = [] - var question: MultipleChoiceQuestion - - init(question: MultipleChoiceQuestion) { - self.question = question - super.init(frame: .zero) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func display() { - let buttonStackView = UIStackView() - buttonStackView.axis = .vertical - buttonStackView.distribution = .fillEqually - buttonStackView.spacing = 10 - buttonStackView.translatesAutoresizingMaskIntoConstraints = false - self.addSubview(buttonStackView) - - buttonStackView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - buttonStackView.centerYAnchor.constraint(equalTo: self.centerYAnchor) - ]) - - // 객관식 선택지 버튼 생성 - for index in 0..<4 { - let button = UIButton() - button.setTitle(question.choices[index], for: .normal) - button.setTitleColor(.black, for: .normal) - button.layer.cornerRadius = 20 - button.backgroundColor = UIColor(hexString: "#F9DF56") - button.tag = index - - buttonStackView.addArrangedSubview(button) - choiceButtons.append(button) - } - - // AutoLayout 설정 - for button in choiceButtons { - button.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - button.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20), - button.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), - button.heightAnchor.constraint(equalToConstant: 50) - ]) - } - } -} diff --git a/Helfy/View/Question/QuestionView.swift b/Helfy/View/Question/QuestionView.swift deleted file mode 100644 index 4399130..0000000 --- a/Helfy/View/Question/QuestionView.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// QuestionView.swift -// Helfy -// -// Created by 윤성은 on 11/22/23. -// - -import UIKit - -enum QuestionType { - case MultipleQuestion - case TrueOrFalseQuestion -} - -class QuestionView: UIView { - var text: String - var image: UIImage? - - init(text: String, image: UIImage? = nil) { - self.text = text - self.image = image - super.init(frame: .zero) - setLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // 텍스트 - let questionText: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.numberOfLines = 0 - label.font = .boldSystemFont(ofSize: 22) - label.textAlignment = .center - return label - }() - - // 이미지 - let questionImage: UIImageView = { - let image: UIImageView = UIImageView() - image.translatesAutoresizingMaskIntoConstraints = false - image.contentMode = .scaleAspectFit - return image - }() - - func setLayout() { - addSubview(questionImage) - addSubview(questionText) - - questionImage.image = self.image - questionText.text = self.text - - // 이미지가 있을 때 - if self.image != nil { - NSLayoutConstraint.activate([ - questionImage.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 30), - questionImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10), - questionImage.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10), - questionImage.heightAnchor.constraint(equalToConstant: 200) - ]) - - NSLayoutConstraint.activate([ - questionText.topAnchor.constraint(equalTo: questionImage.bottomAnchor, constant: 20), - questionText.centerXAnchor.constraint(equalTo: self.centerXAnchor), - questionText.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20), - questionText.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), - questionText.bottomAnchor.constraint(equalTo: self.bottomAnchor), - ]) - } - // 이미지가 없을 때 - else { - NSLayoutConstraint.activate([ - questionText.topAnchor.constraint(equalTo: self.topAnchor, constant: 20), - questionText.centerXAnchor.constraint(equalTo: self.centerXAnchor), - questionText.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20), - questionText.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), - questionText.bottomAnchor.constraint(equalTo: self.bottomAnchor), - ]) - } - } -} diff --git a/Helfy/View/Question/QuizView.swift b/Helfy/View/Question/QuizView.swift new file mode 100644 index 0000000..97910a5 --- /dev/null +++ b/Helfy/View/Question/QuizView.swift @@ -0,0 +1,229 @@ +// +// QuestionView.swift +// Helfy +// +// Created by 윤성은 on 11/22/23. +// + +import UIKit + +enum QuizType { + case MULTIPLE_CHOICE + case OX +} + +class QuizView: UIView { + var quizType: QuizType { + didSet { + print("QuizType didSet") + + update() + } + } +// var newChoice = Choices(choice1: "", choice2: "", choice3: "", choice4: "") + var newChoice: [String: String]? + var arr: [String] = [] + + var buttonStackView: UIStackView + var choiceButtons: [UIButton] = [] + var trueButton: UIButton = UIButton() + var falseButton: UIButton = UIButton() + + let quizNumber: UILabel = { + let label = UILabel() + label.font = .boldSystemFont(ofSize: 17) + return label + }() + + // 텍스트 및 이미지 설정 + let quizText: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + label.font = .boldSystemFont(ofSize: 22) + label.textAlignment = .center + return label + }() + + let quizImage: UIImageView = { + let image: UIImageView = UIImageView() + image.contentMode = .scaleAspectFit + return image + }() + + init(frame: CGRect, quizType: QuizType) { + self.quizType = quizType + self.buttonStackView = UIStackView() + super.init(frame: frame) + update() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var didSelectChoice: ((String) -> Void)? + + @objc func buttonClicked(_ button: UIButton) { + guard let choice = button.titleLabel?.text else { + return + } + + // 버튼 클릭 이벤트를 외부로 알리는 클로저 호출 + didSelectChoice?(choice) + } + + private func setLayout() { + print("setLayout method is called") + + self.addSubview(quizNumber) + self.addSubview(quizImage) + self.addSubview(quizText) + + quizNumber.translatesAutoresizingMaskIntoConstraints = false + quizImage.translatesAutoresizingMaskIntoConstraints = false + quizText.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + quizNumber.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10), + quizNumber.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30), + + quizImage.topAnchor.constraint(equalTo: quizNumber.bottomAnchor, constant: 50), + quizImage.centerXAnchor.constraint(equalTo: self.centerXAnchor), + quizImage.widthAnchor.constraint(equalToConstant: 300), + quizImage.heightAnchor.constraint(equalToConstant: 100), + + quizText.centerXAnchor.constraint(equalTo: self.centerXAnchor), + quizText.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20), + quizText.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), + ]) + } + + func updateImageLayout() { + if let _ = quizImage.image { + // 이미지가 있을 때의 레이아웃 설정 + NSLayoutConstraint.activate([ + quizText.topAnchor.constraint(equalTo: self.quizImage.bottomAnchor, constant: 20), + ]) + } else { + // 이미지가 없을 때의 레이아웃 설정 + NSLayoutConstraint.activate([ + quizText.topAnchor.constraint(equalTo: self.quizNumber.bottomAnchor, constant: 100), + ]) + } + } + + private func update() { + // 먼저 모든 버튼을 제거 + for button in choiceButtons { + button.removeFromSuperview() + } + choiceButtons.removeAll() + + trueButton.removeFromSuperview() + falseButton.removeFromSuperview() + + setLayout() + + switch quizType { + case .MULTIPLE_CHOICE: + buttonStackView = { + let buttonStack = UIStackView() + buttonStack.axis = .vertical + buttonStack.distribution = .fillEqually + buttonStack.spacing = 10 + + return buttonStack + }() + + self.addSubview(buttonStackView) + + buttonStackView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + buttonStackView.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), + buttonStackView.centerXAnchor.constraint(equalTo: self.centerXAnchor), + buttonStackView.centerYAnchor.constraint(equalTo: self.centerYAnchor), + buttonStackView.widthAnchor.constraint(equalToConstant: 300), + buttonStackView.heightAnchor.constraint(equalToConstant: 220) + ]) + + updateMultipleChoiceUI(with: self.newChoice) + + break + + case .OX: + trueButton = UIButton() + trueButton.setTitle("O", for: .normal) + trueButton.titleLabel?.font = .systemFont(ofSize: 50) + trueButton.backgroundColor = UIColor(hexString: "#F9DF56") + trueButton.layer.cornerRadius = 20 + trueButton.tag = 1 + + falseButton = UIButton() + falseButton.setTitle("X", for: .normal) + falseButton.titleLabel?.font = .systemFont(ofSize: 50) + falseButton.backgroundColor = UIColor(hexString: "#F9A456") + falseButton.layer.cornerRadius = 20 + falseButton.tag = 0 + + self.addSubview(trueButton) + self.addSubview(falseButton) + + trueButton.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + falseButton.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + + // AutoLayout 설정 + trueButton.translatesAutoresizingMaskIntoConstraints = false + falseButton.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + trueButton.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 70), + trueButton.heightAnchor.constraint(equalToConstant: 150), + trueButton.widthAnchor.constraint(equalToConstant: 100), + trueButton.trailingAnchor.constraint(equalTo: self.centerXAnchor, constant: -15), + + falseButton.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 70), + falseButton.leadingAnchor.constraint(equalTo: self.centerXAnchor, constant: 15), + falseButton.heightAnchor.constraint(equalToConstant: 150), + falseButton.widthAnchor.constraint(equalToConstant: 100), + + trueButton.centerYAnchor.constraint(equalTo: self.centerYAnchor), + falseButton.centerYAnchor.constraint(equalTo: self.centerYAnchor) + ]) + + + break + } + } + + func updateMultipleChoiceUI(with choices: [String: String]?) { + if let unwrappedChoices = choices { + arr = Array(unwrappedChoices.values) + } else { + print("choices is nil") + } + guard let choices = choices else { + return + } + + // 기존의 버튼들을 제거 + for button in choiceButtons { + button.removeFromSuperview() + } + choiceButtons.removeAll() + + // 새로운 선택지로 버튼을 생성하여 스택뷰에 추가 + for (key, choice) in choices { + let button = UIButton() + button.setTitle(choice, for: .normal) + button.setTitleColor(.black, for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 20) + button.layer.cornerRadius = 20 + button.backgroundColor = UIColor(hexString: "#F9DF56") + button.tag = Int(key) ?? 0 + button.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + + buttonStackView.addArrangedSubview(button) + choiceButtons.append(button) + } + } +} diff --git a/Helfy/View/Question/TrueOrFalseQuestionView.swift b/Helfy/View/Question/TrueOrFalseQuizView.swift similarity index 100% rename from Helfy/View/Question/TrueOrFalseQuestionView.swift rename to Helfy/View/Question/TrueOrFalseQuizView.swift diff --git a/Helfy/View/Quiz/QuizHomeView.swift b/Helfy/View/Quiz/QuizHomeView.swift new file mode 100644 index 0000000..c18f886 --- /dev/null +++ b/Helfy/View/Quiz/QuizHomeView.swift @@ -0,0 +1,128 @@ +// +// QuizView.swift +// Helfy +// +// Created by 윤성은 on 2023/12/19. +// + +import UIKit + +class QuizHomeView: UIView { + var scoreLabel: UILabel = { + let label = UILabel() + label.text = "나의 점수 : " + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.textAlignment = .right + label.sizeToFit() + return label + }() + + let idLabel: UILabel = { + let label = UILabel() + label.text = "님" + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.sizeToFit() + return label + }() + + let exLabel: UILabel = { + let label = UILabel() + label.text = "오늘은 어떤 퀴즈를 풀어볼까요?" + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.sizeToFit() + return label + }() + + let todayButton: UIButton = createButton(withTitle: "오늘의 퀴즈") + let quizButton: UIButton = createButton(withTitle: "퀴즈 풀어보기") + let wrongButton: UIButton = createButton(withTitle: "오답 다시 풀어보기") + + static func createButton(withTitle title: String) -> UIButton { + let button = UIButton(type: .system) + button.setTitle(title, for: .normal) + + button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 22) + button.backgroundColor = UIColor(hexString:"#F9DF56") + button.layer.cornerRadius = 20 + button.setTitleColor(UIColor.black, for:.normal) + + button.heightAnchor.constraint(equalToConstant: 50).isActive = true + button.widthAnchor.constraint(equalToConstant: 330).isActive = true + + return button + } + + override init(frame:CGRect) { + super.init(frame:frame) + + let containerView: UIView = { + let containerView = UIView() + containerView.backgroundColor = UIColor(hexString:"#F9DF56") + containerView.addSubview(scoreLabel) + containerView.addSubview(idLabel) + containerView.addSubview(exLabel) + return containerView + }() + + let buttonStack: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.distribution = .fill + stackView.spacing = 20 + return stackView + }() + + self.backgroundColor = UIColor.white + + buttonStack.addArrangedSubview(todayButton) + buttonStack.addArrangedSubview(quizButton) + buttonStack.addArrangedSubview(wrongButton) + + addSubview(containerView) + addSubview(buttonStack) + + scoreLabel.translatesAutoresizingMaskIntoConstraints = false + idLabel.translatesAutoresizingMaskIntoConstraints = false + exLabel.translatesAutoresizingMaskIntoConstraints = false + + containerView.translatesAutoresizingMaskIntoConstraints = false + buttonStack.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + + scoreLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 50), + scoreLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -20), + + idLabel.topAnchor.constraint(equalTo: scoreLabel.topAnchor, constant: 70), + idLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20), + + exLabel.topAnchor.constraint(equalTo: idLabel.topAnchor, constant: 30), + exLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20), + + containerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor), + containerView.centerXAnchor.constraint(equalTo: self.centerXAnchor), + containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor), + containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor), + + buttonStack.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 50), + buttonStack.centerXAnchor.constraint(equalTo: self.centerXAnchor), + buttonStack.centerYAnchor.constraint(equalTo: self.centerYAnchor), +// buttonStack.widthAnchor.constraint(equalToConstant: 330), +// buttonStack.heightAnchor.constraint(equalToConstant: 200), +// buttonStack.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.8), +// buttonStack.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.4) + + ]) + } + + required init?(coder aDecoder:NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Helfy/View/Quiz/QuizView.swift b/Helfy/View/Quiz/QuizView.swift new file mode 100644 index 0000000..f476680 --- /dev/null +++ b/Helfy/View/Quiz/QuizView.swift @@ -0,0 +1,186 @@ +// +// QuestionView.swift +// Helfy +// +// Created by 윤성은 on 11/22/23. +// + +import UIKit + +enum QuizType: String { + case MULTIPLE_CHOICE = "MULTIPLE_CHOICE" + case OX = "OX" +} + +class QuizView: UIView { + var quizType: QuizType { + didSet { + print("QuizType didSet") + + update(quizType) + } + } + + var newChoice: [String: String]? + var arr: [String] = [] + + var buttonStackView: UIStackView + var choiceButtons: [UIButton] = [] + var trueButton: UIButton = UIButton() + var falseButton: UIButton = UIButton() + + let quizNumber: UILabel = { + let label = UILabel() + label.font = .boldSystemFont(ofSize: 17) + return label + }() + + let quizText: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + label.font = .boldSystemFont(ofSize: 22) + label.textAlignment = .center + return label + }() + + let quizImage: UIImageView = { + let image: UIImageView = UIImageView() + image.contentMode = .scaleAspectFit + image.clipsToBounds = true + return image + }() + + init(frame: CGRect, quizType: QuizType) { + self.quizType = quizType + self.buttonStackView = UIStackView() + super.init(frame: frame) + update(quizType) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var didSelectChoice: ((String) -> Void)? + + @objc func buttonClicked(_ button: UIButton) { + guard let choice = button.titleLabel?.text else { + return + } + + didSelectChoice?(choice) + } + + func update(_ quizType: QuizType) { + for button in choiceButtons { + button.removeFromSuperview() + } + choiceButtons.removeAll() + + trueButton.removeFromSuperview() + falseButton.removeFromSuperview() + + setUpLayout() + + switch quizType { + case .MULTIPLE_CHOICE: + buttonStackView.axis = .vertical + buttonStackView.spacing = 10 + buttonStackView.distribution = .fillEqually + + guard let newChoice = newChoice else { + return + } + + for (key, choice) in newChoice { + let button = UIButton() + button.setTitle(choice, for: .normal) + button.setTitleColor(.black, for: .normal) + button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20) + button.layer.cornerRadius = 20 + button.backgroundColor = UIColor(hexString: "#F9DF56") + button.tag = Int(key) ?? 0 + button.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + + buttonStackView.addArrangedSubview(button) + choiceButtons.append(button) + } + + case .OX: + buttonStackView.axis = .horizontal + buttonStackView.spacing = 13 + buttonStackView.distribution = .fillEqually + + trueButton = UIButton() + trueButton.setTitle("O", for: .normal) + trueButton.titleLabel?.font = .systemFont(ofSize: 50) + trueButton.backgroundColor = UIColor(hexString: "#F9DF56") + trueButton.layer.cornerRadius = 20 + trueButton.tag = 1 + trueButton.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + + falseButton = UIButton() + falseButton.setTitle("X", for: .normal) + falseButton.titleLabel?.font = .systemFont(ofSize: 50) + falseButton.backgroundColor = UIColor(hexString: "#F9A456") + falseButton.layer.cornerRadius = 20 + falseButton.tag = 0 + falseButton.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside) + + buttonStackView.addArrangedSubview(trueButton) + buttonStackView.addArrangedSubview(falseButton) + } + } + + var quizTextTopConstraint: NSLayoutConstraint? + + func setUpLayout() { + addSubview(quizNumber) + addSubview(quizText) + addSubview(quizImage) + addSubview(buttonStackView) + + quizNumber.translatesAutoresizingMaskIntoConstraints = false + quizText.translatesAutoresizingMaskIntoConstraints = false + quizImage.translatesAutoresizingMaskIntoConstraints = false + buttonStackView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + quizNumber.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 20), + quizNumber.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30), + +// quizText.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20), +// quizText.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), + quizText.centerXAnchor.constraint(equalTo: self.centerXAnchor), + + quizImage.topAnchor.constraint(equalTo: quizText.bottomAnchor, constant: 50), + quizImage.centerXAnchor.constraint(equalTo: self.centerXAnchor), + quizImage.widthAnchor.constraint(equalToConstant: 250), + quizImage.heightAnchor.constraint(equalToConstant: 200), + + buttonStackView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -50), +// buttonStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30), +// buttonStackView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -30), + buttonStackView.centerXAnchor.constraint(equalTo: self.centerXAnchor), + buttonStackView.heightAnchor.constraint(equalToConstant: 230), + buttonStackView.widthAnchor.constraint(equalToConstant: 330) + ]) + + updateImageLayout() + } + + func updateImageLayout() { + if quizImage.image == nil { + quizImage.isHidden = true + quizTextTopConstraint?.isActive = false + quizTextTopConstraint = quizText.topAnchor.constraint(equalTo: quizNumber.bottomAnchor, constant: 100) + quizTextTopConstraint?.isActive = true + } else { + quizImage.isHidden = false + quizTextTopConstraint?.isActive = false + quizTextTopConstraint = quizText.topAnchor.constraint(equalTo: quizNumber.bottomAnchor, constant: 50) + quizTextTopConstraint?.isActive = true + } + self.layoutIfNeeded() + } +} diff --git a/Helfy/View/QuizHomeView.swift b/Helfy/View/QuizHomeView.swift new file mode 100644 index 0000000..e9c3507 --- /dev/null +++ b/Helfy/View/QuizHomeView.swift @@ -0,0 +1,122 @@ +// +// QuizView.swift +// Helfy +// +// Created by 윤성은 on 2023/12/19. +// + +import UIKit + +class QuizHomeView: UIView { + var scoreLabel: UILabel = { + let label = UILabel() + label.text = "나의 점수 : " + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.textAlignment = .right + label.sizeToFit() + return label + }() + + let idLabel: UILabel = { + let label = UILabel() + label.text = "님" + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.sizeToFit() + return label + }() + + let exLabel: UILabel = { + let label = UILabel() + label.text = "오늘은 어떤 퀴즈를 풀어볼까요?" + label.textColor = UIColor.black + label.font = UIFont.boldSystemFont(ofSize: 25) + label.numberOfLines = 0 + label.sizeToFit() + return label + }() + + let todayButton: UIButton = createButton(withTitle: "오늘의 퀴즈") + let quizButton: UIButton = createButton(withTitle: "퀴즈 풀어보기") + let wrongButton: UIButton = createButton(withTitle: "오답 다시 풀어보기") + + static func createButton(withTitle title: String) -> UIButton { + let button = UIButton(type: .system) + button.setTitle(title, for: .normal) + + button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 22) + button.backgroundColor = UIColor(hexString:"#F9DF56") + button.layer.cornerRadius = 20 + button.setTitleColor(UIColor.black, for:.normal) + + button.heightAnchor.constraint(equalToConstant: 50).isActive = true + button.widthAnchor.constraint(equalToConstant: 300).isActive = true + + return button + } + + override init(frame:CGRect) { + super.init(frame:frame) + + let containerView: UIView = { + let containerView = UIView() + containerView.backgroundColor = UIColor(hexString:"#F9DF56") + containerView.addSubview(scoreLabel) + containerView.addSubview(idLabel) + containerView.addSubview(exLabel) + return containerView + }() + + let buttonStack: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.spacing = 20 + return stackView + }() + + self.backgroundColor = UIColor.white + + buttonStack.addArrangedSubview(todayButton) + buttonStack.addArrangedSubview(quizButton) + buttonStack.addArrangedSubview(wrongButton) + + addSubview(containerView) + addSubview(buttonStack) + + scoreLabel.translatesAutoresizingMaskIntoConstraints = false + idLabel.translatesAutoresizingMaskIntoConstraints = false + exLabel.translatesAutoresizingMaskIntoConstraints = false + + containerView.translatesAutoresizingMaskIntoConstraints = false + buttonStack.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + + scoreLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 50), + scoreLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -20), + idLabel.topAnchor.constraint(equalTo: scoreLabel.topAnchor, constant: 70), + idLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20), + + exLabel.topAnchor.constraint(equalTo: idLabel.topAnchor, constant: 30), + exLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20), + + containerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor), + containerView.centerXAnchor.constraint(equalTo: self.centerXAnchor), + containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor), + containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor), + + buttonStack.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 50), + buttonStack.centerXAnchor.constraint(equalTo: self.centerXAnchor), + buttonStack.centerYAnchor.constraint(equalTo: self.centerYAnchor), + buttonStack.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.8) + ]) + } + + required init?(coder aDecoder:NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Helfy/View/QuizView.swift b/Helfy/View/QuizView.swift deleted file mode 100644 index 86366e7..0000000 --- a/Helfy/View/QuizView.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// QuizView.swift -// Helfy -// -// Created by 김하은 on 2023/10/11. -// -import UIKit - -class QuizView: UIView { - -}