From 5336eb08cd6497f0958f3f39fa075ab2b95dc3b3 Mon Sep 17 00:00:00 2001 From: seungbong88 Date: Sat, 23 Apr 2022 04:41:52 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8F=AC=EC=BC=93=EB=AA=AC=20API=20=EC=95=B1?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PokemonProject.xcodeproj/project.pbxproj | 489 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/PokemonProject.xcscheme | 78 +++ .../xcschemes/xcschememanagement.plist | 14 + .../xcschemes/xcschememanagement.plist | 22 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 ++++ .../Assets.xcassets/Contents.json | 6 + .../pokeball.imageset/Contents.json | 21 + .../pokeball.imageset/pokeball.png | Bin 0 -> 3236 bytes .../pokedex.imageset/Contents.json | 21 + .../pokedex.imageset/pokedex.png | Bin 0 -> 2799 bytes .../professor_oh.imageset/Contents.json | 21 + .../professor_oh.imageset/professor_oh.png | Bin 0 -> 42619 bytes .../Base.lproj/LaunchScreen.storyboard | 25 + .../PokemonProject/Base.lproj/Main.storyboard | 213 ++++++++ .../PokemonProject/Common/ImageCache.swift | 23 + .../Common/ImageDownloader.swift | 52 ++ .../PokemonProject/Common/NetworkAgent.swift | 78 +++ .../Common/NetworkConstants.swift | 15 + .../Extension/UIView+Extension.swift | 42 ++ .../UIViewController+Extension.swift | 19 + .../PokemonProject/PokemonProject/Info.plist | 25 + .../PokemonProject/Model/PokeHabitat.swift | 36 ++ .../PokemonProject/Model/PokeSpecies.swift | 86 +++ .../PokemonProject/Model/Pokemon.swift | 47 ++ .../PokemonProject/Model/TotalHabitat.swift | 29 ++ .../PokemonProject/Model/User.swift | 27 + .../PokemonProject/System/AppDelegate.swift | 25 + .../PokemonProject/System/SceneDelegate.swift | 33 ++ .../PokemonProject/View/HabitatCell.swift | 19 + .../PokemonProject/View/HabitatCell.xib | 40 ++ .../PokemonProject/View/PokedexCell.swift | 19 + .../PokemonProject/View/PokedexCell.xib | 42 ++ .../View/PokedexDescriptionView.swift | 44 ++ .../View/PokedexDescriptionView.xib | 87 ++++ .../ViewController/FieldViewController.swift | 145 ++++++ .../ViewController/MapViewController.swift | 97 ++++ .../PokedexViewController.swift | 74 +++ 40 files changed, 2138 insertions(+) create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/pokedex.png create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift create mode 100644 seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/PokedexViewController.swift diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e340dc3 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj @@ -0,0 +1,489 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 0B547619280D35020046BDB3 /* FieldViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B547618280D35020046BDB3 /* FieldViewController.swift */; }; + 0B54761C280D4CC90046BDB3 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */; }; + F70FE55F2813371C009858DE /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70FE55E2813371C009858DE /* UIViewController+Extension.swift */; }; + F72A5FB0280C5F3D005DEF66 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FAF280C5F3D005DEF66 /* User.swift */; }; + F72A5FB3280C6033005DEF66 /* PokedexCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB2280C6033005DEF66 /* PokedexCell.swift */; }; + F72A5FB5280C605A005DEF66 /* PokedexCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F72A5FB4280C605A005DEF66 /* PokedexCell.xib */; }; + F72A5FB7280C60F3005DEF66 /* PokedexViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */; }; + F72A5FBB280C66D6005DEF66 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB9280C66D6005DEF66 /* ImageCache.swift */; }; + F72A5FBC280C66D6005DEF66 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */; }; + F72A5FBE280C6FEC005DEF66 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */; }; + F72A5FC3280C711B005DEF66 /* HabitatCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FC1280C711B005DEF66 /* HabitatCell.swift */; }; + F72A5FC4280C711B005DEF66 /* HabitatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F72A5FC2280C711B005DEF66 /* HabitatCell.xib */; }; + F72A5FC6280C72E3005DEF66 /* TotalHabitat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */; }; + F73FA2C72811BD3800C62123 /* PokedexDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */; }; + F73FA2C92811BD5100C62123 /* PokedexDescriptionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */; }; + F78EEC8F2809C16100EBF148 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EEC8E2809C16100EBF148 /* AppDelegate.swift */; }; + F78EEC912809C16100EBF148 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EEC902809C16100EBF148 /* SceneDelegate.swift */; }; + F78EEC962809C16100EBF148 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC942809C16100EBF148 /* Main.storyboard */; }; + F78EEC982809C16300EBF148 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC972809C16300EBF148 /* Assets.xcassets */; }; + F78EEC9B2809C16300EBF148 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */; }; + F78EECA52809C1F500EBF148 /* Pokemon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA42809C1F500EBF148 /* Pokemon.swift */; }; + F78EECA82809C23B00EBF148 /* PokeSpecies.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA72809C23B00EBF148 /* PokeSpecies.swift */; }; + F78EECAA2809C88A00EBF148 /* PokeHabitat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA92809C88A00EBF148 /* PokeHabitat.swift */; }; + F78EECAE2809C96500EBF148 /* NetworkAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECAD2809C96500EBF148 /* NetworkAgent.swift */; }; + F78EECB02809C97A00EBF148 /* NetworkConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0B547618280D35020046BDB3 /* FieldViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldViewController.swift; sourceTree = ""; }; + 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; + F70FE55E2813371C009858DE /* UIViewController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extension.swift"; sourceTree = ""; }; + F72A5FAF280C5F3D005DEF66 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + F72A5FB2280C6033005DEF66 /* PokedexCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexCell.swift; sourceTree = ""; }; + F72A5FB4280C605A005DEF66 /* PokedexCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PokedexCell.xib; sourceTree = ""; }; + F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexViewController.swift; sourceTree = ""; }; + F72A5FB9280C66D6005DEF66 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = ""; }; + F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = ""; }; + F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + F72A5FC1280C711B005DEF66 /* HabitatCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HabitatCell.swift; sourceTree = ""; }; + F72A5FC2280C711B005DEF66 /* HabitatCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HabitatCell.xib; sourceTree = ""; }; + F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalHabitat.swift; sourceTree = ""; }; + F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexDescriptionView.swift; sourceTree = ""; }; + F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PokedexDescriptionView.xib; sourceTree = ""; }; + F78EEC8B2809C16100EBF148 /* PokemonProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PokemonProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F78EEC8E2809C16100EBF148 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + F78EEC902809C16100EBF148 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + F78EEC952809C16100EBF148 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + F78EEC972809C16300EBF148 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + F78EEC9A2809C16300EBF148 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + F78EEC9C2809C16300EBF148 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F78EECA42809C1F500EBF148 /* Pokemon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pokemon.swift; sourceTree = ""; }; + F78EECA72809C23B00EBF148 /* PokeSpecies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokeSpecies.swift; sourceTree = ""; }; + F78EECA92809C88A00EBF148 /* PokeHabitat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokeHabitat.swift; sourceTree = ""; }; + F78EECAD2809C96500EBF148 /* NetworkAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkAgent.swift; sourceTree = ""; }; + F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConstants.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F78EEC882809C16100EBF148 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0B54761A280D4CBC0046BDB3 /* Extension */ = { + isa = PBXGroup; + children = ( + 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */, + F70FE55E2813371C009858DE /* UIViewController+Extension.swift */, + ); + path = Extension; + sourceTree = ""; + }; + F72A5FAD280C5C95005DEF66 /* ViewController */ = { + isa = PBXGroup; + children = ( + F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */, + F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */, + 0B547618280D35020046BDB3 /* FieldViewController.swift */, + ); + path = ViewController; + sourceTree = ""; + }; + F72A5FAE280C5CE4005DEF66 /* System */ = { + isa = PBXGroup; + children = ( + F78EEC8E2809C16100EBF148 /* AppDelegate.swift */, + F78EEC902809C16100EBF148 /* SceneDelegate.swift */, + ); + path = System; + sourceTree = ""; + }; + F72A5FB1280C601B005DEF66 /* View */ = { + isa = PBXGroup; + children = ( + F72A5FB2280C6033005DEF66 /* PokedexCell.swift */, + F72A5FB4280C605A005DEF66 /* PokedexCell.xib */, + F72A5FC1280C711B005DEF66 /* HabitatCell.swift */, + F72A5FC2280C711B005DEF66 /* HabitatCell.xib */, + F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */, + F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */, + ); + path = View; + sourceTree = ""; + }; + F72A5FB8280C66B0005DEF66 /* Common */ = { + isa = PBXGroup; + children = ( + F72A5FB9280C66D6005DEF66 /* ImageCache.swift */, + F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */, + F78EECAD2809C96500EBF148 /* NetworkAgent.swift */, + F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */, + ); + path = Common; + sourceTree = ""; + }; + F78EEC822809C16100EBF148 = { + isa = PBXGroup; + children = ( + F78EEC8D2809C16100EBF148 /* PokemonProject */, + F78EEC8C2809C16100EBF148 /* Products */, + ); + sourceTree = ""; + }; + F78EEC8C2809C16100EBF148 /* Products */ = { + isa = PBXGroup; + children = ( + F78EEC8B2809C16100EBF148 /* PokemonProject.app */, + ); + name = Products; + sourceTree = ""; + }; + F78EEC8D2809C16100EBF148 /* PokemonProject */ = { + isa = PBXGroup; + children = ( + 0B54761A280D4CBC0046BDB3 /* Extension */, + F72A5FAE280C5CE4005DEF66 /* System */, + F72A5FB8280C66B0005DEF66 /* Common */, + F78EECA32809C1E600EBF148 /* Model */, + F72A5FB1280C601B005DEF66 /* View */, + F72A5FAD280C5C95005DEF66 /* ViewController */, + F78EEC942809C16100EBF148 /* Main.storyboard */, + F78EEC972809C16300EBF148 /* Assets.xcassets */, + F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */, + F78EEC9C2809C16300EBF148 /* Info.plist */, + ); + path = PokemonProject; + sourceTree = ""; + }; + F78EECA32809C1E600EBF148 /* Model */ = { + isa = PBXGroup; + children = ( + F78EECA42809C1F500EBF148 /* Pokemon.swift */, + F78EECA72809C23B00EBF148 /* PokeSpecies.swift */, + F78EECA92809C88A00EBF148 /* PokeHabitat.swift */, + F72A5FAF280C5F3D005DEF66 /* User.swift */, + F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */, + ); + path = Model; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F78EEC8A2809C16100EBF148 /* PokemonProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = F78EEC9F2809C16300EBF148 /* Build configuration list for PBXNativeTarget "PokemonProject" */; + buildPhases = ( + F78EEC872809C16100EBF148 /* Sources */, + F78EEC882809C16100EBF148 /* Frameworks */, + F78EEC892809C16100EBF148 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PokemonProject; + productName = PokemonProject; + productReference = F78EEC8B2809C16100EBF148 /* PokemonProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F78EEC832809C16100EBF148 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1320; + LastUpgradeCheck = 1320; + TargetAttributes = { + F78EEC8A2809C16100EBF148 = { + CreatedOnToolsVersion = 13.2.1; + }; + }; + }; + buildConfigurationList = F78EEC862809C16100EBF148 /* Build configuration list for PBXProject "PokemonProject" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F78EEC822809C16100EBF148; + productRefGroup = F78EEC8C2809C16100EBF148 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F78EEC8A2809C16100EBF148 /* PokemonProject */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F78EEC892809C16100EBF148 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F73FA2C92811BD5100C62123 /* PokedexDescriptionView.xib in Resources */, + F72A5FC4280C711B005DEF66 /* HabitatCell.xib in Resources */, + F72A5FB5280C605A005DEF66 /* PokedexCell.xib in Resources */, + F78EEC9B2809C16300EBF148 /* LaunchScreen.storyboard in Resources */, + F78EEC982809C16300EBF148 /* Assets.xcassets in Resources */, + F78EEC962809C16100EBF148 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F78EEC872809C16100EBF148 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F78EECB02809C97A00EBF148 /* NetworkConstants.swift in Sources */, + F72A5FBC280C66D6005DEF66 /* ImageDownloader.swift in Sources */, + 0B547619280D35020046BDB3 /* FieldViewController.swift in Sources */, + F78EECA52809C1F500EBF148 /* Pokemon.swift in Sources */, + F78EECAA2809C88A00EBF148 /* PokeHabitat.swift in Sources */, + F72A5FB3280C6033005DEF66 /* PokedexCell.swift in Sources */, + F73FA2C72811BD3800C62123 /* PokedexDescriptionView.swift in Sources */, + F78EECA82809C23B00EBF148 /* PokeSpecies.swift in Sources */, + F70FE55F2813371C009858DE /* UIViewController+Extension.swift in Sources */, + F72A5FBB280C66D6005DEF66 /* ImageCache.swift in Sources */, + F72A5FB0280C5F3D005DEF66 /* User.swift in Sources */, + F72A5FC3280C711B005DEF66 /* HabitatCell.swift in Sources */, + F72A5FB7280C60F3005DEF66 /* PokedexViewController.swift in Sources */, + 0B54761C280D4CC90046BDB3 /* UIView+Extension.swift in Sources */, + F78EEC8F2809C16100EBF148 /* AppDelegate.swift in Sources */, + F78EECAE2809C96500EBF148 /* NetworkAgent.swift in Sources */, + F78EEC912809C16100EBF148 /* SceneDelegate.swift in Sources */, + F72A5FC6280C72E3005DEF66 /* TotalHabitat.swift in Sources */, + F72A5FBE280C6FEC005DEF66 /* MapViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + F78EEC942809C16100EBF148 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F78EEC952809C16100EBF148 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F78EEC9A2809C16300EBF148 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + F78EEC9D2809C16300EBF148 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + F78EEC9E2809C16300EBF148 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + F78EECA02809C16300EBF148 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = QKG65XDLX8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PokemonProject/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.bong.Pokemon; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F78EECA12809C16300EBF148 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = QKG65XDLX8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PokemonProject/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.bong.Pokemon; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F78EEC862809C16100EBF148 /* Build configuration list for PBXProject "PokemonProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F78EEC9D2809C16300EBF148 /* Debug */, + F78EEC9E2809C16300EBF148 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F78EEC9F2809C16300EBF148 /* Build configuration list for PBXNativeTarget "PokemonProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F78EECA02809C16300EBF148 /* Debug */, + F78EECA12809C16300EBF148 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F78EEC832809C16100EBF148 /* Project object */; +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme new file mode 100644 index 0000000..fdfcd50 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..fc2b161 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + PokemonProject.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..c682335 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + PokemonProject.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + F78EEC8A2809C16100EBF148 + + primary + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json new file mode 100644 index 0000000..9e84fe4 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "pokeball.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png new file mode 100644 index 0000000000000000000000000000000000000000..077d0d3bde44c81a8ebb1cee6a3ba622c59c9e3b GIT binary patch literal 3236 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 BQmg;~ literal 0 HcmV?d00001 diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json new file mode 100644 index 0000000..706380e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "professor_oh.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png new file mode 100644 index 0000000000000000000000000000000000000000..a4ca25c815069cb466dffe0ff1184e0357e6b2d7 GIT binary patch literal 42619 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 literal 0 HcmV?d00001 diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard new file mode 100644 index 0000000..6990b28 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift new file mode 100644 index 0000000..ca53b2d --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift @@ -0,0 +1,23 @@ +// +// Cache.swift +// ImageCache +// +// Created by seungbong on 2022/03/26. +// + +import UIKit + +class ImageCache { + private static var imageCache: NSCache? + + static var shared: NSCache { + if imageCache == nil { + imageCache = NSCache() + } + return imageCache! + } + + static func clear() { + imageCache = nil + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift new file mode 100644 index 0000000..b30b46d --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift @@ -0,0 +1,52 @@ +// +// ImageDownloader.swift +// ImageCachingProject +// +// Created by seungbong on 2022/03/26. +// + +import UIKit + +class ImageDownloader { + + private static var imageDownloader: ImageDownloader? + + static var shared: ImageDownloader { + if imageDownloader == nil { + imageDownloader = ImageDownloader() + } + return imageDownloader! + } + + func downloadImage(from urlString: String, + completion: @escaping (UIImage?)->Void) { + let cacheKey: String = urlString + if let image = cachedImage(key: urlString) { + completion(image) + return + } + + DispatchQueue.global().async { + guard let url = URL(string: urlString), + let data = try? Data(contentsOf: url), + let loadedImage = UIImage(data: data) else { + completion(nil) + return + } + self.saveLoadedImage(key: cacheKey, image: loadedImage) + completion(loadedImage) + } + } + + private func cachedImage(key: String) -> UIImage? { + return ImageCache.shared.object(forKey: key as NSString) + } + + private func saveLoadedImage(key: String, image: UIImage) { + ImageCache.shared.setObject(image, forKey: key as NSString) + } + + func clearCache() { + ImageCache.clear() + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift new file mode 100644 index 0000000..7b71d24 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift @@ -0,0 +1,78 @@ +// +// NetworkAgent.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +class NetworkAgent { + + enum NetworkError: Error { + case invalidUrl + case serverError + case parsingError + } + + static var shared = NetworkAgent() + + func requestGET(_ urlString: String, completion: @escaping (Data)->Void) { + guard let url = URL(string: urlString) else { return } + + let urlRequest = URLRequest(url: url) + let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in + if let error = error { + self.handledClientError(error) + return + } + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + self.handledServerError(response) + return + } + + guard let data = data else { return } + completion(data) + + } + task.resume() + } + + func requestGET(_ urlString: String, + responseType: T.Type, + completion: @escaping (T)->Void) { + guard let url = URL(string: urlString) else { return } + + let urlRequest = URLRequest(url: url) + let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in + if let error = error { + self.handledClientError(error) + return + } + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + self.handledServerError(response) + return + } + + guard let data = data else { return } + let decoder = JSONDecoder() + if let json = try? decoder.decode(T.self, from: data) { + completion(json) + } else { + print("parsing error") + } + } + task.resume() + } + + // MARK: - Error Handling + private func handledClientError(_ error: Error) { + print("[client] \(error.localizedDescription)") + } + + private func handledServerError(_ response: URLResponse?) { + print("[server] \(response?.description ?? "")") + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift new file mode 100644 index 0000000..df095d6 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift @@ -0,0 +1,15 @@ +// +// NetworkConstants.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +class NetworkConstants { + + static let pokemonAPI = "https://pokeapi.co/api/v2/pokemon/" // 포켓몬 API + static let speciesAPI = "https://pokeapi.co/api/v2/pokemon-species" // 포켓몬 종류 API + static let habitateAPI = "https://pokeapi.co/api/v2/pokemon-habitat" // 포켓몬 서식지 API +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift new file mode 100644 index 0000000..c1b2249 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift @@ -0,0 +1,42 @@ +// +// UIView+Extension.swift +// PokemonProject +// +// Created by seunghee on 2022/04/18. +// + +import UIKit + +extension UIView { + func startRotate() { + DispatchQueue.main.async { + let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") + rotation.fromValue = 0 + rotation.toValue = NSNumber(value: M_PI * 2) + rotation.duration = 2 + rotation.isCumulative = true + rotation.repeatCount = FLT_MAX + self.layer.add(rotation, forKey: "rotationAnimation") + } + } + + func stopRotate() { + DispatchQueue.main.async { + self.layer.removeAnimation(forKey: "rotationAnimation") + } + } + + func setCornerRadius(_ radius: CGFloat = 20.0) { + self.layer.cornerRadius = radius + } + + func setConstraintEqualTo(_ view: UIView) { + self.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + self.leadingAnchor.constraint(equalTo: view.leadingAnchor), + self.trailingAnchor.constraint(equalTo: view.trailingAnchor), + self.topAnchor.constraint(equalTo: view.topAnchor), + self.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift new file mode 100644 index 0000000..36245b6 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift @@ -0,0 +1,19 @@ +// +// UIViewController+Extension.swift +// PokemonProject +// +// Created by seungbong on 2022/04/23. +// + +import UIKit + +extension UIViewController { + func showAlert(message: String) { + DispatchQueue.main.async { + let alert = UIAlertController(title: "안내", + message: message, + preferredStyle: .alert) + self.present(alert, animated: true, completion: nil) + } + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist new file mode 100644 index 0000000..dd3c9af --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift new file mode 100644 index 0000000..172d22e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift @@ -0,0 +1,36 @@ +// +// PokeHabitat.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +struct PokeHabitat: Codable { + var id: Int + var name: String + var speciesInfoList: [PokeSpeciesInfo] + + var response: Response? + + init(json: Response) { + self.id = json.id + self.name = json.name + self.speciesInfoList = json.pokemon_species ?? [] + } +} + +// MARK: - Poke Species Property Types +extension PokeHabitat { + struct Response: Codable { + var id: Int + var name: String + var pokemon_species: [PokeSpeciesInfo]? + } + + struct PokeSpeciesInfo: Codable { + var name: String + var url: String + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift new file mode 100644 index 0000000..868e4f8 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift @@ -0,0 +1,86 @@ +// +// PokeSpecies.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +struct PokeSpecies: Codable { + + var id: Int + var name: String + var habitatName: String // 서식지 + var captureRate: Int // 포획률 (the higher the number, the easier the catch, 0~255) + var type: String + var descriptions: [String] + var habitat: NameUrlInfo? + + init(json: Response) { + self.id = json.id + self.name = PokeSpecies.korLanguage(from: json.names) ?? json.name + self.type = PokeSpecies.korType(from: json.genera) + self.habitat = json.habitat + self.captureRate = json.capture_rate + self.habitatName = json.habitat?.name ?? "" + self.descriptions = PokeSpecies.descriptionList(from: json.flavor_text_entries) + } + + + static func korLanguage(from nameList: [LanguageInfo]) -> String? { + let korName = nameList.filter{$0.language.name == "ko"}.first.map({$0.name}) + return (korName?.count == 0) ? nil : korName + } + + static func korType(from generaInfo: [GeneraInfo]) -> String { + return generaInfo.filter{$0.language.name == "ko"}.first.map({$0.genus}) ?? "???" + } + + static func descriptionList(from infoList: [DescriptionInfo]) -> [String] { + var list: [String] = [] + for info in infoList { + if info.language.name == "ko" && list.contains(info.flavor_text) == false { + list.append(info.flavor_text) + } + } + return list + } +} + +// MARK: - Poke Species Property Types +extension PokeSpecies { + + struct Response: Codable { + var id: Int + var name: String + var names: [LanguageInfo] + var habitat: NameUrlInfo? + var capture_rate: Int + var flavor_text_entries: [DescriptionInfo] + var genera: [GeneraInfo] + } + + struct NameUrlInfo: Codable { + var name: String + var url: String + } + + struct LanguageInfo: Codable { + var name: String + var language: NameUrlInfo + } + + struct DescriptionInfo: Codable { + var flavor_text: String + var language: NameUrlInfo + var version: NameUrlInfo + } + + struct GeneraInfo: Codable { + var genus: String + var language: NameUrlInfo + } +} + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift new file mode 100644 index 0000000..9cd5098 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift @@ -0,0 +1,47 @@ +// +// Pokemon.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +struct Pokemon { + var id: Int + var name: String + var species: SpaiesInfo? + var sprites: SpriteInfo? + + var spriteImages: [UIImage] = [] + var pokeSpacies: PokeSpecies? + + init(json: Response) { + self.id = json.id + self.name = json.name + self.species = json.species + self.sprites = json.sprites + } +} + +// MARK: - Poke Species Property Types +extension Pokemon { + struct Response: Codable { + var id: Int + var name: String + var species: SpaiesInfo? + var sprites: SpriteInfo? + } + + struct SpaiesInfo: Codable { + var name: String + var url: String + } + + struct SpriteInfo: Codable { + var back_default: String? + var back_shiny: String? + var front_default: String? + var front_shiny: String? + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift new file mode 100644 index 0000000..1153753 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift @@ -0,0 +1,29 @@ +// +// TotalHabitat.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import Foundation + +struct TotalHabitat { + var habitatInfoList: [HabitatInfo] + + init(json: Response) { + self.habitatInfoList = json.results + } +} + +// MARK: - Poke Species Property Types +extension TotalHabitat { + struct Response: Codable { + var results: [HabitatInfo] + } + + struct HabitatInfo: Codable { + var name: String + var url: String + + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift new file mode 100644 index 0000000..924ea34 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift @@ -0,0 +1,27 @@ +// +// User.swift +// PokemonProject +// +// Created by seungbong on 2022/04/17. +// + +import Foundation + +class User { + private static var user: User? + + static var shared: User { + if User.user == nil { + User.user = User() + } + return User.user! + } + + var ownedPokemonList: [Pokemon] = [] + + func addPokemon(_ pokemon: Pokemon) { + if ownedPokemonList.filter({$0.id == pokemon.id}).isEmpty { + ownedPokemonList.append(pokemon) + } + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift new file mode 100644 index 0000000..f1f2bd3 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift @@ -0,0 +1,25 @@ +// +// AppDelegate.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + return true + } + + // MARK: UISceneSession Lifecycle + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift new file mode 100644 index 0000000..66f3588 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift @@ -0,0 +1,33 @@ +// +// SceneDelegate.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + } + + func sceneDidBecomeActive(_ scene: UIScene) { + } + + func sceneWillResignActive(_ scene: UIScene) { + } + + func sceneWillEnterForeground(_ scene: UIScene) { + } + + func sceneDidEnterBackground(_ scene: UIScene) { + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift new file mode 100644 index 0000000..1879c08 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift @@ -0,0 +1,19 @@ +// +// HabitatCell.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import UIKit + +class HabitatCell: UICollectionViewCell { + + @IBOutlet weak var habitatNameLabel: UILabel! + + static let id = "HabitatCell" + + override func prepareForReuse() { + habitatNameLabel.text = "" + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib new file mode 100644 index 0000000..71072a1 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift new file mode 100644 index 0000000..678e619 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift @@ -0,0 +1,19 @@ +// +// PokedexCell.swift +// PokemonProject +// +// Created by seungbong on 2022/04/17. +// + +import UIKit + +class PokedexCell: UICollectionViewCell { + + static let id = "PokedexCell" + + @IBOutlet weak var pokemonImageView: UIImageView! + + override func prepareForReuse() { + pokemonImageView.image = nil + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib new file mode 100644 index 0000000..b02d7db --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift new file mode 100644 index 0000000..2e430c4 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift @@ -0,0 +1,44 @@ +// +// DescriptionView.swift +// PokemonProject +// +// Created by seungbong on 2022/04/22. +// + + +import UIKit + +class PokedexDescriptionView: UIView { + private let id = "PokedexDescriptionView" + @IBOutlet weak var descriptionLabel: UILabel! + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + let view = Bundle.main.loadNibNamed(id, owner: self, options: nil)?.first as! UIView + view.frame = self.bounds + self.addSubview(view) + } + + func updateLabel(species: PokeSpecies) { + var descriptionText = "이름: \(species.name)\n타입: \(species.type)" + for description in species.descriptions { + let textRemovedLineSpacing = description.replacingOccurrences(of: "\n", with: " ") + descriptionText += "\n\(textRemovedLineSpacing)" + } + descriptionLabel.text = descriptionText + } + + @IBAction func closeButtonDidTap(_ sender: Any) { + self.removeFromSuperview() + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib new file mode 100644 index 0000000..ccd086e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift new file mode 100644 index 0000000..fecb064 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift @@ -0,0 +1,145 @@ +// +// FieldViewController.swift +// PokemonProject +// +// Created by seunghee on 2022/04/18. +// + +import UIKit + +class FieldViewController: UIViewController { + + @IBOutlet weak var pokemonImageView: UIImageView! + @IBOutlet weak var pokemonNameLabel: UILabel! + @IBOutlet weak var descriptionLabel: UILabel! + + static let id = "FieldViewController" + + var pokeSpecies: PokeSpecies? + var pokemon: Pokemon? + + enum CatchResult { + case captured + case miss + case runAway + + var description: String { + switch self { + case .captured: return "을(를) 잡았다!" + case .miss: return "이(가) 잡히지 않았다." + case .runAway: return "이(가) 도망갔다." + } + } + + var textColor: UIColor { + switch self { + case .captured: return .orange + case .miss: return .black + case .runAway: return .cyan + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + fetchPokemon() + configureView() + } + + private func configureView(){ + pokemonNameLabel.text = pokeSpecies?.name ?? "??" + descriptionLabel.text = "이(가) 나타났다!" + descriptionLabel.textColor = .black + } + + private func fetchPokemon() { + guard let species = pokeSpecies else { return } + + let urlString = NetworkConstants.pokemonAPI + "\(species.id)" + NetworkAgent.shared.requestGET(urlString, responseType: Pokemon.Response.self) { [weak self] response in + guard let self = self else { return } + + self.pokemon = Pokemon(json: response) + self.pokemon?.pokeSpacies = self.pokeSpecies + self.fetchPokemonImage() + } + } + + private func fetchPokemonImage() { + guard let pokemon = pokemon, + let sprites = pokemon.sprites else { return } + + let imageUrls = [sprites.front_default, sprites.front_shiny, sprites.back_default] + for imageUrl in imageUrls { + ImageDownloader.shared.downloadImage(from: imageUrl ?? "") { [weak self] pokemonImage in + guard let self = self else { return } + + DispatchQueue.main.async { + if imageUrl == sprites.front_default { + self.pokemonImageView.image = pokemonImage + self.pokemonImageView.startRotate() + } + } + } + } + } + + @IBAction func throwButtonDidTap(_ sender: Any) { + let captureResult = getCatchResult() + updateView(state: captureResult) + } + + private func getCatchResult() -> CatchResult { + let captureRate: Int = pokeSpecies?.captureRate ?? 0 + let runAwayRate: Int = Int(Double(255 - captureRate) * 0.3) + let random = Int.random(in: 0...255) + print("\(random) / \(captureRate) / \(runAwayRate)") + + if random <= captureRate { + return .captured + } else if random <= runAwayRate { + return .runAway + } else { + return .miss + } + } + + private func updateView(state: CatchResult) { + guard let pokemon = self.pokemon else { return } + descriptionLabel.text = state.description + descriptionLabel.textColor = state.textColor + + switch state { + case .captured: + User.shared.addPokemon(pokemon) + changeImageView(url: pokemon.sprites?.front_shiny ?? "", isRotate: false) + dismissViewController() + case .runAway: + changeImageView(url: pokemon.sprites?.back_default ?? "", isRotate: false) + dismissViewController() + case .miss: + break + } + } + + private func changeImageView(url: String, isRotate: Bool = false) { + ImageDownloader.shared.downloadImage(from: url, completion: { image in + DispatchQueue.main.async { + self.pokemonImageView.image = image + if isRotate { + self.pokemonImageView.startRotate() + } else { + self.pokemonImageView.stopRotate() + } + } + }) + } + + private func dismissViewController() { + self.view.isUserInteractionEnabled = false + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5, execute: { + self.navigationController?.popViewController(animated: true) + }) + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift new file mode 100644 index 0000000..56c1d39 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift @@ -0,0 +1,97 @@ +// +// MapViewController.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import UIKit + +class MapViewController: UIViewController { + + @IBOutlet weak var mapCollectionView: UICollectionView! + + static let id = "MapViewController" + + var totalHabitat: TotalHabitat? + var loadedHabitatList: [PokeHabitat] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + fetchTotalHabitat() + configureView() + } + + private func configureView() { + let layout = UICollectionViewFlowLayout() + layout.itemSize = CGSize(width: 120, height: 120) + mapCollectionView.collectionViewLayout = layout + mapCollectionView.dataSource = self + mapCollectionView.delegate = self + + let nib = UINib(nibName: HabitatCell.id, bundle: nil) + mapCollectionView.register(nib, forCellWithReuseIdentifier: HabitatCell.id) + } + + private func fetchTotalHabitat() { + NetworkAgent.shared.requestGET(NetworkConstants.habitateAPI, + responseType: TotalHabitat.Response.self) { response in + self.totalHabitat = TotalHabitat(json: response) + DispatchQueue.main.async { + self.mapCollectionView.reloadData() + } + } + } + + private func fetchHabitat(url: String, completion: @escaping (PokeHabitat)->Void) { + NetworkAgent.shared.requestGET(url, responseType: PokeHabitat.Response.self) { response in + completion(PokeHabitat(json: response)) + } + } + + private func fetchSpecies(url: String, completion: @escaping (PokeSpecies)->Void) { + NetworkAgent.shared.requestGET(url, responseType: PokeSpecies.Response.self) { response in + completion(PokeSpecies(json: response)) + } + } +} + +// MARK: - CollectionView Delegate +extension MapViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return totalHabitat?.habitatInfoList.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HabitatCell.id, for: indexPath) as? HabitatCell else { + return UICollectionViewCell() + } + + guard let habitatList = totalHabitat else { return UICollectionViewCell() } + + cell.habitatNameLabel.text = habitatList.habitatInfoList[indexPath.row].name + cell.setCornerRadius() + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedHabitatUrl = totalHabitat?.habitatInfoList[indexPath.row].url ?? "" + fetchHabitat(url: selectedHabitatUrl, completion: { [weak self] habiatat in + guard let self = self else { return } + + let random = Int.random(in: 0.. Int { + return User.shared.ownedPokemonList.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PokedexCell.id, for: indexPath) as? PokedexCell else { + return UICollectionViewCell() + } + + let pokemon = User.shared.ownedPokemonList[indexPath.row] + let downloadUrl = pokemon.sprites?.front_default ?? "" + ImageDownloader.shared.downloadImage(from: downloadUrl) { image in + DispatchQueue.main.async { + cell.pokemonImageView.image = image + } + } + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedPokemon = User.shared.ownedPokemonList[indexPath.row] + guard let species = selectedPokemon.pokeSpacies else { return } + let descriptionView = PokedexDescriptionView() + descriptionView.updateLabel(species: species) + self.view.addSubview(descriptionView) + descriptionView.setConstraintEqualTo(self.view) + } +}