diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..93d7a6e5e --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Gcc Patch +/*.gcno + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.toptal.com/developers/gitignore/api/xcode diff --git a/SideDish/SideDish.xcodeproj/project.pbxproj b/SideDish/SideDish.xcodeproj/project.pbxproj new file mode 100644 index 000000000..8e502e1af --- /dev/null +++ b/SideDish/SideDish.xcodeproj/project.pbxproj @@ -0,0 +1,771 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 10418377262E9B9B00280647 /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10418376262E9B9B00280647 /* Card.swift */; }; + 1041837D262E9F3B00280647 /* ImageView+load.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1041837C262E9F3B00280647 /* ImageView+load.swift */; }; + 10418385262EA17300280647 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10418384262EA17300280647 /* Section.swift */; }; + 10418397262EB1B700280647 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10418396262EB1B700280647 /* Response.swift */; }; + 1041839F262EB30800280647 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1041839E262EB30800280647 /* API.swift */; }; + 104183A5262EB35A00280647 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 104183A4262EB35A00280647 /* Alamofire */; }; + 104BDDD926315DF300F35BE7 /* EndPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 104BDDD826315DF300F35BE7 /* EndPoint.swift */; }; + 1050395B262DAAA000C8C0FB /* Toaster in Frameworks */ = {isa = PBXBuildFile; productRef = 1050395A262DAAA000C8C0FB /* Toaster */; }; + 10503968262DAB9300C8C0FB /* SectionHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10503967262DAB9300C8C0FB /* SectionHeaderReusableView.swift */; }; + 105467172631101600DAB4E3 /* LoadError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 105467162631101600DAB4E3 /* LoadError.swift */; }; + 1054672426311A6900DAB4E3 /* APITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1054672326311A6900DAB4E3 /* APITest.swift */; }; + 10B9F8A626311DF800B3130D /* CardAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10B9F8A526311DF800B3130D /* CardAPI.swift */; }; + 10B9F8B02631536400B3130D /* NotoSansKR-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 1086ED2B262FF720004B8D42 /* NotoSansKR-Bold.otf */; }; + 10B9F8B42631536700B3130D /* NotoSansKR-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 1086ED2A262FF720004B8D42 /* NotoSansKR-Regular.otf */; }; + B3D25402262D6AC900F57C61 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D25401262D6AC900F57C61 /* AppDelegate.swift */; }; + B3D25404262D6AC900F57C61 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D25403262D6AC900F57C61 /* SceneDelegate.swift */; }; + B3D25406262D6AC900F57C61 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D25405262D6AC900F57C61 /* ViewController.swift */; }; + B3D25409262D6AC900F57C61 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B3D25407262D6AC900F57C61 /* Main.storyboard */; }; + B3D2540C262D6AC900F57C61 /* SideDish.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B3D2540A262D6AC900F57C61 /* SideDish.xcdatamodeld */; }; + B3D2540E262D6ACA00F57C61 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B3D2540D262D6ACA00F57C61 /* Assets.xcassets */; }; + B3D25411262D6ACA00F57C61 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B3D2540F262D6ACA00F57C61 /* LaunchScreen.storyboard */; }; + B3D2541C262D6ACA00F57C61 /* SideDishTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D2541B262D6ACA00F57C61 /* SideDishTests.swift */; }; + B3D25427262D6ACA00F57C61 /* SideDishUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D25426262D6ACA00F57C61 /* SideDishUITests.swift */; }; + B3D25439262D6ECA00F57C61 /* CardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3D25437262D6ECA00F57C61 /* CardCell.swift */; }; + B3D2543A262D6ECA00F57C61 /* CardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B3D25438262D6ECA00F57C61 /* CardCell.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + B3D25418262D6ACA00F57C61 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B3D253F6262D6AC900F57C61 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B3D253FD262D6AC900F57C61; + remoteInfo = SideDish; + }; + B3D25423262D6ACA00F57C61 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B3D253F6262D6AC900F57C61 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B3D253FD262D6AC900F57C61; + remoteInfo = SideDish; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 10418376262E9B9B00280647 /* Card.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Card.swift; sourceTree = ""; }; + 1041837C262E9F3B00280647 /* ImageView+load.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ImageView+load.swift"; sourceTree = ""; }; + 10418384262EA17300280647 /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; + 10418396262EB1B700280647 /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = ""; }; + 1041839E262EB30800280647 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; + 104BDDD826315DF300F35BE7 /* EndPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndPoint.swift; sourceTree = ""; }; + 10503967262DAB9300C8C0FB /* SectionHeaderReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderReusableView.swift; sourceTree = ""; }; + 105467162631101600DAB4E3 /* LoadError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadError.swift; sourceTree = ""; }; + 1054672326311A6900DAB4E3 /* APITest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APITest.swift; sourceTree = ""; }; + 1086ED2A262FF720004B8D42 /* NotoSansKR-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSansKR-Regular.otf"; sourceTree = ""; }; + 1086ED2B262FF720004B8D42 /* NotoSansKR-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSansKR-Bold.otf"; sourceTree = ""; }; + 10B9F8A526311DF800B3130D /* CardAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardAPI.swift; sourceTree = ""; }; + B3D253FE262D6AC900F57C61 /* SideDish.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SideDish.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B3D25401262D6AC900F57C61 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B3D25403262D6AC900F57C61 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + B3D25405262D6AC900F57C61 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + B3D25408262D6AC900F57C61 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B3D2540B262D6AC900F57C61 /* SideDish.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SideDish.xcdatamodel; sourceTree = ""; }; + B3D2540D262D6ACA00F57C61 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B3D25410262D6ACA00F57C61 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B3D25412262D6ACA00F57C61 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B3D25417262D6ACA00F57C61 /* SideDishTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SideDishTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B3D2541B262D6ACA00F57C61 /* SideDishTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideDishTests.swift; sourceTree = ""; }; + B3D2541D262D6ACA00F57C61 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B3D25422262D6ACA00F57C61 /* SideDishUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SideDishUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B3D25426262D6ACA00F57C61 /* SideDishUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideDishUITests.swift; sourceTree = ""; }; + B3D25428262D6ACA00F57C61 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B3D25437262D6ECA00F57C61 /* CardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardCell.swift; sourceTree = ""; }; + B3D25438262D6ECA00F57C61 /* CardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CardCell.xib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B3D253FB262D6AC900F57C61 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1050395B262DAAA000C8C0FB /* Toaster in Frameworks */, + 104183A5262EB35A00280647 /* Alamofire in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D25414262D6ACA00F57C61 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D2541F262D6ACA00F57C61 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1041837B262E9F2500280647 /* Extension */ = { + isa = PBXGroup; + children = ( + 1041837C262E9F3B00280647 /* ImageView+load.swift */, + ); + path = Extension; + sourceTree = ""; + }; + 10418395262EB0CF00280647 /* Network */ = { + isa = PBXGroup; + children = ( + 105467162631101600DAB4E3 /* LoadError.swift */, + 1041839E262EB30800280647 /* API.swift */, + 10B9F8A526311DF800B3130D /* CardAPI.swift */, + 10418396262EB1B700280647 /* Response.swift */, + 104BDDD826315DF300F35BE7 /* EndPoint.swift */, + ); + path = Network; + sourceTree = ""; + }; + 1086ED24262FF5FA004B8D42 /* Fonts */ = { + isa = PBXGroup; + children = ( + 1086ED2B262FF720004B8D42 /* NotoSansKR-Bold.otf */, + 1086ED2A262FF720004B8D42 /* NotoSansKR-Regular.otf */, + ); + path = Fonts; + sourceTree = ""; + }; + 108A8942262E761400C828AC /* Model */ = { + isa = PBXGroup; + children = ( + 10418376262E9B9B00280647 /* Card.swift */, + 10418384262EA17300280647 /* Section.swift */, + ); + path = Model; + sourceTree = ""; + }; + B3D253F5262D6AC900F57C61 = { + isa = PBXGroup; + children = ( + B3D25400262D6AC900F57C61 /* SideDish */, + B3D2541A262D6ACA00F57C61 /* SideDishTests */, + B3D25425262D6ACA00F57C61 /* SideDishUITests */, + B3D253FF262D6AC900F57C61 /* Products */, + ); + sourceTree = ""; + }; + B3D253FF262D6AC900F57C61 /* Products */ = { + isa = PBXGroup; + children = ( + B3D253FE262D6AC900F57C61 /* SideDish.app */, + B3D25417262D6ACA00F57C61 /* SideDishTests.xctest */, + B3D25422262D6ACA00F57C61 /* SideDishUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + B3D25400262D6AC900F57C61 /* SideDish */ = { + isa = PBXGroup; + children = ( + 1086ED24262FF5FA004B8D42 /* Fonts */, + 1041837B262E9F2500280647 /* Extension */, + B3D25443262D6F2A00F57C61 /* Storyboard */, + 10418395262EB0CF00280647 /* Network */, + 108A8942262E761400C828AC /* Model */, + B3D25441262D6F0300F57C61 /* Controller */, + B3D2543F262D6EF500F57C61 /* View */, + B3D25401262D6AC900F57C61 /* AppDelegate.swift */, + B3D25403262D6AC900F57C61 /* SceneDelegate.swift */, + B3D2540D262D6ACA00F57C61 /* Assets.xcassets */, + B3D2540F262D6ACA00F57C61 /* LaunchScreen.storyboard */, + B3D25412262D6ACA00F57C61 /* Info.plist */, + B3D2540A262D6AC900F57C61 /* SideDish.xcdatamodeld */, + ); + path = SideDish; + sourceTree = ""; + }; + B3D2541A262D6ACA00F57C61 /* SideDishTests */ = { + isa = PBXGroup; + children = ( + B3D2541B262D6ACA00F57C61 /* SideDishTests.swift */, + B3D2541D262D6ACA00F57C61 /* Info.plist */, + 1054672326311A6900DAB4E3 /* APITest.swift */, + ); + path = SideDishTests; + sourceTree = ""; + }; + B3D25425262D6ACA00F57C61 /* SideDishUITests */ = { + isa = PBXGroup; + children = ( + B3D25426262D6ACA00F57C61 /* SideDishUITests.swift */, + B3D25428262D6ACA00F57C61 /* Info.plist */, + ); + path = SideDishUITests; + sourceTree = ""; + }; + B3D2543F262D6EF500F57C61 /* View */ = { + isa = PBXGroup; + children = ( + B3D25437262D6ECA00F57C61 /* CardCell.swift */, + B3D25438262D6ECA00F57C61 /* CardCell.xib */, + 10503967262DAB9300C8C0FB /* SectionHeaderReusableView.swift */, + ); + path = View; + sourceTree = ""; + }; + B3D25441262D6F0300F57C61 /* Controller */ = { + isa = PBXGroup; + children = ( + B3D25405262D6AC900F57C61 /* ViewController.swift */, + ); + path = Controller; + sourceTree = ""; + }; + B3D25443262D6F2A00F57C61 /* Storyboard */ = { + isa = PBXGroup; + children = ( + B3D25407262D6AC900F57C61 /* Main.storyboard */, + ); + path = Storyboard; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B3D253FD262D6AC900F57C61 /* SideDish */ = { + isa = PBXNativeTarget; + buildConfigurationList = B3D2542B262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDish" */; + buildPhases = ( + B3D253FA262D6AC900F57C61 /* Sources */, + B3D253FB262D6AC900F57C61 /* Frameworks */, + B3D253FC262D6AC900F57C61 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SideDish; + packageProductDependencies = ( + 1050395A262DAAA000C8C0FB /* Toaster */, + 104183A4262EB35A00280647 /* Alamofire */, + ); + productName = SideDish; + productReference = B3D253FE262D6AC900F57C61 /* SideDish.app */; + productType = "com.apple.product-type.application"; + }; + B3D25416262D6ACA00F57C61 /* SideDishTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B3D2542E262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDishTests" */; + buildPhases = ( + B3D25413262D6ACA00F57C61 /* Sources */, + B3D25414262D6ACA00F57C61 /* Frameworks */, + B3D25415262D6ACA00F57C61 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + B3D25419262D6ACA00F57C61 /* PBXTargetDependency */, + ); + name = SideDishTests; + productName = SideDishTests; + productReference = B3D25417262D6ACA00F57C61 /* SideDishTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + B3D25421262D6ACA00F57C61 /* SideDishUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B3D25431262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDishUITests" */; + buildPhases = ( + B3D2541E262D6ACA00F57C61 /* Sources */, + B3D2541F262D6ACA00F57C61 /* Frameworks */, + B3D25420262D6ACA00F57C61 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + B3D25424262D6ACA00F57C61 /* PBXTargetDependency */, + ); + name = SideDishUITests; + productName = SideDishUITests; + productReference = B3D25422262D6ACA00F57C61 /* SideDishUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B3D253F6262D6AC900F57C61 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1240; + LastUpgradeCheck = 1240; + TargetAttributes = { + B3D253FD262D6AC900F57C61 = { + CreatedOnToolsVersion = 12.4; + }; + B3D25416262D6ACA00F57C61 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = B3D253FD262D6AC900F57C61; + }; + B3D25421262D6ACA00F57C61 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = B3D253FD262D6AC900F57C61; + }; + }; + }; + buildConfigurationList = B3D253F9262D6AC900F57C61 /* Build configuration list for PBXProject "SideDish" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B3D253F5262D6AC900F57C61; + packageReferences = ( + 10503959262DAAA000C8C0FB /* XCRemoteSwiftPackageReference "Toaster" */, + 104183A3262EB35A00280647 /* XCRemoteSwiftPackageReference "Alamofire" */, + ); + productRefGroup = B3D253FF262D6AC900F57C61 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B3D253FD262D6AC900F57C61 /* SideDish */, + B3D25416262D6ACA00F57C61 /* SideDishTests */, + B3D25421262D6ACA00F57C61 /* SideDishUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B3D253FC262D6AC900F57C61 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B3D25411262D6ACA00F57C61 /* LaunchScreen.storyboard in Resources */, + B3D2540E262D6ACA00F57C61 /* Assets.xcassets in Resources */, + B3D25409262D6AC900F57C61 /* Main.storyboard in Resources */, + B3D2543A262D6ECA00F57C61 /* CardCell.xib in Resources */, + 10B9F8B42631536700B3130D /* NotoSansKR-Regular.otf in Resources */, + 10B9F8B02631536400B3130D /* NotoSansKR-Bold.otf in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D25415262D6ACA00F57C61 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D25420262D6ACA00F57C61 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B3D253FA262D6AC900F57C61 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 105467172631101600DAB4E3 /* LoadError.swift in Sources */, + 1041839F262EB30800280647 /* API.swift in Sources */, + 10418385262EA17300280647 /* Section.swift in Sources */, + 10B9F8A626311DF800B3130D /* CardAPI.swift in Sources */, + 1041837D262E9F3B00280647 /* ImageView+load.swift in Sources */, + B3D25439262D6ECA00F57C61 /* CardCell.swift in Sources */, + 10503968262DAB9300C8C0FB /* SectionHeaderReusableView.swift in Sources */, + 10418397262EB1B700280647 /* Response.swift in Sources */, + 10418377262E9B9B00280647 /* Card.swift in Sources */, + B3D25406262D6AC900F57C61 /* ViewController.swift in Sources */, + B3D25402262D6AC900F57C61 /* AppDelegate.swift in Sources */, + B3D2540C262D6AC900F57C61 /* SideDish.xcdatamodeld in Sources */, + 104BDDD926315DF300F35BE7 /* EndPoint.swift in Sources */, + B3D25404262D6AC900F57C61 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D25413262D6ACA00F57C61 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1054672426311A6900DAB4E3 /* APITest.swift in Sources */, + B3D2541C262D6ACA00F57C61 /* SideDishTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B3D2541E262D6ACA00F57C61 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B3D25427262D6ACA00F57C61 /* SideDishUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + B3D25419262D6ACA00F57C61 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B3D253FD262D6AC900F57C61 /* SideDish */; + targetProxy = B3D25418262D6ACA00F57C61 /* PBXContainerItemProxy */; + }; + B3D25424262D6ACA00F57C61 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B3D253FD262D6AC900F57C61 /* SideDish */; + targetProxy = B3D25423262D6ACA00F57C61 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + B3D25407262D6AC900F57C61 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B3D25408262D6AC900F57C61 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B3D2540F262D6ACA00F57C61 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B3D25410262D6ACA00F57C61 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B3D25429262D6ACA00F57C61 /* 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++14"; + 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 = 14.4; + 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; + }; + B3D2542A262D6ACA00F57C61 /* 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++14"; + 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 = 14.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B3D2542C262D6ACA00F57C61 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDish/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDish; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B3D2542D262D6ACA00F57C61 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDish/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDish; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + B3D2542F262D6ACA00F57C61 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDishTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDishTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SideDish.app/SideDish"; + }; + name = Debug; + }; + B3D25430262D6ACA00F57C61 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDishTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDishTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SideDish.app/SideDish"; + }; + name = Release; + }; + B3D25432262D6ACA00F57C61 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDishUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDishUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = SideDish; + }; + name = Debug; + }; + B3D25433262D6ACA00F57C61 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = B3PWYBKFUK; + INFOPLIST_FILE = SideDishUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = zeke.SideDishUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = SideDish; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B3D253F9262D6AC900F57C61 /* Build configuration list for PBXProject "SideDish" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B3D25429262D6ACA00F57C61 /* Debug */, + B3D2542A262D6ACA00F57C61 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B3D2542B262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDish" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B3D2542C262D6ACA00F57C61 /* Debug */, + B3D2542D262D6ACA00F57C61 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B3D2542E262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDishTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B3D2542F262D6ACA00F57C61 /* Debug */, + B3D25430262D6ACA00F57C61 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B3D25431262D6ACA00F57C61 /* Build configuration list for PBXNativeTarget "SideDishUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B3D25432262D6ACA00F57C61 /* Debug */, + B3D25433262D6ACA00F57C61 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 104183A3262EB35A00280647 /* XCRemoteSwiftPackageReference "Alamofire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Alamofire/Alamofire.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.2.0; + }; + }; + 10503959262DAAA000C8C0FB /* XCRemoteSwiftPackageReference "Toaster" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/devxoul/Toaster.git"; + requirement = { + branch = master; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 104183A4262EB35A00280647 /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = 104183A3262EB35A00280647 /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; + 1050395A262DAAA000C8C0FB /* Toaster */ = { + isa = XCSwiftPackageProductDependency; + package = 10503959262DAAA000C8C0FB /* XCRemoteSwiftPackageReference "Toaster" */; + productName = Toaster; + }; +/* End XCSwiftPackageProductDependency section */ + +/* Begin XCVersionGroup section */ + B3D2540A262D6AC900F57C61 /* SideDish.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + B3D2540B262D6AC900F57C61 /* SideDish.xcdatamodel */, + ); + currentVersion = B3D2540B262D6AC900F57C61 /* SideDish.xcdatamodel */; + path = SideDish.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = B3D253F6262D6AC900F57C61 /* Project object */; +} diff --git a/SideDish/SideDish.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SideDish/SideDish.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/SideDish/SideDish.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..a251b87b2 --- /dev/null +++ b/SideDish/SideDish.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,25 @@ +{ + "object": { + "pins": [ + { + "package": "Alamofire", + "repositoryURL": "https://github.com/Alamofire/Alamofire.git", + "state": { + "branch": null, + "revision": "4d19ad82f80cc71ff829b941ded114c56f4f604c", + "version": "5.4.2" + } + }, + { + "package": "Toaster", + "repositoryURL": "https://github.com/devxoul/Toaster.git", + "state": { + "branch": "master", + "revision": "b4fa1aa8d9231ea62dac5c3255f4313d727d22a4", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/SideDish/SideDish/AppDelegate.swift b/SideDish/SideDish/AppDelegate.swift new file mode 100644 index 000000000..69823dc51 --- /dev/null +++ b/SideDish/SideDish/AppDelegate.swift @@ -0,0 +1,81 @@ +// +// AppDelegate.swift +// SideDish +// +// Created by 양준혁 on 2021/04/19. +// + +import UIKit +import CoreData + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + // MARK: - Core Data stack + + lazy var persistentContainer: NSPersistentContainer = { + /* + The persistent container for the application. This implementation + creates and returns a container, having loaded the store for the + application to it. This property is optional since there are legitimate + error conditions that could cause the creation of the store to fail. + */ + let container = NSPersistentContainer(name: "SideDish") + container.loadPersistentStores(completionHandler: { (storeDescription, error) in + if let error = error as NSError? { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + /* + Typical reasons for an error here include: + * The parent directory does not exist, cannot be created, or disallows writing. + * The persistent store is not accessible, due to permissions or data protection when the device is locked. + * The device is out of space. + * The store could not be migrated to the current model version. + Check the error message to determine what the actual problem was. + */ + fatalError("Unresolved error \(error), \(error.userInfo)") + } + }) + return container + }() + + // MARK: - Core Data Saving support + + func saveContext () { + let context = persistentContainer.viewContext + if context.hasChanges { + do { + try context.save() + } catch { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + let nserror = error as NSError + fatalError("Unresolved error \(nserror), \(nserror.userInfo)") + } + } + } + +} + diff --git a/SideDish/SideDish/Assets.xcassets/AccentColor.colorset/Contents.json b/SideDish/SideDish/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/SideDish/SideDish/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SideDish/SideDish/Assets.xcassets/AppIcon.appiconset/Contents.json b/SideDish/SideDish/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..9221b9bb1 --- /dev/null +++ b/SideDish/SideDish/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/SideDish/SideDish/Assets.xcassets/Contents.json b/SideDish/SideDish/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/SideDish/SideDish/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SideDish/SideDish/Base.lproj/LaunchScreen.storyboard b/SideDish/SideDish/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..865e9329f --- /dev/null +++ b/SideDish/SideDish/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SideDish/SideDish/Controller/ViewController.swift b/SideDish/SideDish/Controller/ViewController.swift new file mode 100644 index 000000000..77b538b25 --- /dev/null +++ b/SideDish/SideDish/Controller/ViewController.swift @@ -0,0 +1,89 @@ +// +// ViewController.swift +// SideDish +// +// Created by 양준혁 on 2021/04/19. +// + +import UIKit +import Toaster +import Combine + +class ViewController: UIViewController { + + // MARK: - Value Types + typealias DataSource = UICollectionViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot + + // MARK: - Properties + @IBOutlet weak var cardCollectionView: UICollectionView! + + private var cancellables: Set = [] + private var sections = Section.allSections + private lazy var dataSource = makeDataSource() + + // MARK: - Life Cycles + override func viewDidLoad() { + super.viewDidLoad() + registerNIB() + fetchData() + makeSectionHeader() + } +} +// MARK: - Functions +extension ViewController { + func makeDataSource() -> DataSource { + let dataSource = DataSource( + collectionView: cardCollectionView, + cellProvider: { ( collectionview, indexPath, card) -> UICollectionViewCell? in + let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "cardCell", for: indexPath) as? CardCell + cell?.card = card + return cell + }) + return dataSource + } + func makeSectionHeader(){ + self.dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in + guard kind == UICollectionView.elementKindSectionHeader else { + return nil + } + let section = self.dataSource.snapshot().sectionIdentifiers[indexPath.section] + let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, + withReuseIdentifier: SectionHeaderReusableView.reuseIdentifier, + for: indexPath) as? SectionHeaderReusableView + headerView?.title.text = section.title + headerView?.configure() + return headerView + } + } + func fetchData(){ + self.sections.forEach{ + $0.$cards.receive(on: DispatchQueue.main) + .sink(receiveValue: {[weak self] _ in + self?.applySnapshot() + }) + .store(in: &cancellables) + } + self.sections[0].loadCards(type: .main) + self.sections[1].loadCards(type: .soup) + self.sections[2].loadCards(type: .side) + } + func applySnapshot(animatingDifferences : Bool = true){ + var snapshot = Snapshot() + snapshot.appendSections(sections) + sections.forEach{ section in + snapshot.appendItems(section.cards, toSection: section) + } + dataSource.apply(snapshot, animatingDifferences: animatingDifferences) + } + func registerNIB() { + let nibName = UINib(nibName: "CardCell", bundle: nil) + cardCollectionView.register(nibName, forCellWithReuseIdentifier: "cardCell") + } +} + +extension ViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: 343, height: 130) + } +} diff --git a/SideDish/SideDish/Extension/ImageView+load.swift b/SideDish/SideDish/Extension/ImageView+load.swift new file mode 100644 index 000000000..11c08471f --- /dev/null +++ b/SideDish/SideDish/Extension/ImageView+load.swift @@ -0,0 +1,24 @@ +// +// ImageView+load.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import UIKit + +extension UIImageView { + func load(url: URL?, completion : @escaping () -> ()) { + guard let url = url else { return } + DispatchQueue.global().async { [weak self] in + if let data = try? Data(contentsOf: url) { + if let image = UIImage(data: data) { + DispatchQueue.main.async { + self?.image = image + completion() + } + } + } + } + } +} diff --git a/SideDish/SideDish/Fonts/NotoSansKR-Bold.otf b/SideDish/SideDish/Fonts/NotoSansKR-Bold.otf new file mode 100644 index 000000000..7f4131ce7 Binary files /dev/null and b/SideDish/SideDish/Fonts/NotoSansKR-Bold.otf differ diff --git a/SideDish/SideDish/Fonts/NotoSansKR-Regular.otf b/SideDish/SideDish/Fonts/NotoSansKR-Regular.otf new file mode 100644 index 000000000..e26c1cd35 Binary files /dev/null and b/SideDish/SideDish/Fonts/NotoSansKR-Regular.otf differ diff --git a/SideDish/SideDish/Info.plist b/SideDish/SideDish/Info.plist new file mode 100644 index 000000000..9dc4db978 --- /dev/null +++ b/SideDish/SideDish/Info.plist @@ -0,0 +1,86 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + http://public.codesquad.kr/ + + NSAllowsArbitraryLoads + + NSTemporaryExceptionAllowsInsecureHTTPLoads + + + + + UIAppFonts + + NotoSansKR-Bold.otf + NotoSansKR-Regular.otf + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/SideDish/SideDish/Model/Card.swift b/SideDish/SideDish/Model/Card.swift new file mode 100644 index 000000000..b2e69ad0b --- /dev/null +++ b/SideDish/SideDish/Model/Card.swift @@ -0,0 +1,35 @@ +// +// Card.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import Foundation + +class Card : Hashable{ + let id : String + + let title : String + let detail : String + let discountPrice : String? + let originalPrice : String? + let imageURL : URL? + let badge : [String]? + + init(id : String, title : String, detail: String, d_price : String?, o_price : String?, url : URL?, badge : [String]?){ + self.id = id + self.title = title + self.detail = detail + self.discountPrice = d_price + self.originalPrice = o_price + self.imageURL = url + self.badge = badge + } + static func == (lhs: Card, rhs: Card) -> Bool { + return lhs.id == rhs.id + } + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } +} diff --git a/SideDish/SideDish/Model/Section.swift b/SideDish/SideDish/Model/Section.swift new file mode 100644 index 000000000..20f95498c --- /dev/null +++ b/SideDish/SideDish/Model/Section.swift @@ -0,0 +1,47 @@ +// +// Section.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import Foundation +import Combine + +class Section : Hashable { + + let title : String + @Published var cards : [Card] + private var cancellables = Set() + + init(title : String, cards : [Card]) { + self.title = title + self.cards = cards + } + func hash(into hasher: inout Hasher) { + hasher.combine(title) + } + static func == (lhs: Section, rhs : Section) -> Bool { + lhs.title == rhs.title + } +} +extension Section { + static let didCardInSectionChanged = Notification.Name("didCardInSectionChanged") +} +extension Section { + static var allSections: [Section] = [ + Section(title: "모두가 좋아하는 든든한 메인요리", + cards: [Card]()), + Section(title: "정성이 담긴 뜨끈뜨끈 국물요리", + cards: [Card]()), + Section(title: "식탁을 풍성하게 하는 정갈한 밑반찬", + cards: [Card]()), + ] + func loadCards(type : EndPoint?){ + guard let type = type else { return } + CardAPI.loadDish(type: type) + .sink(receiveCompletion: { _ in}, + receiveValue: { self.cards = $0.getCards() }) + .store(in: &cancellables) + } +} diff --git a/SideDish/SideDish/Network/API.swift b/SideDish/SideDish/Network/API.swift new file mode 100644 index 000000000..70b02ee02 --- /dev/null +++ b/SideDish/SideDish/Network/API.swift @@ -0,0 +1,48 @@ +// +// API.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import Alamofire +import Foundation +import Combine + +class API { + + struct Response { + let value: T + let response : URLResponse + } + + func run(_ request: DataRequest, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher, APIError> { + + return request + .validate(contentType: ["application/json"]) + .validate() + .publishData(emptyResponseCodes: [200, 204, 205]) + .tryMap { result -> API.Response in + // TODO: Error Handling + + if let data = result.data { + // 응답이 성공이고 result가 있을 때 + let value = try decoder.decode(T.self, from: data) + return Response(value: value, response: result.response!) + } else { + // 응답이 성공이고 result가 없을 때 Empty를 리턴 + return Response(value: Empty.emptyValue() as! T, response: result.response!) + } + } + .mapError({ (error) -> APIError in + if let apiError = error as? APIError { + return apiError + } else { + return .other(error) + } + }) + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() + + } +} diff --git a/SideDish/SideDish/Network/CardAPI.swift b/SideDish/SideDish/Network/CardAPI.swift new file mode 100644 index 000000000..8c9785eb4 --- /dev/null +++ b/SideDish/SideDish/Network/CardAPI.swift @@ -0,0 +1,20 @@ +// +// API.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import Alamofire +import Foundation +import Combine + +class CardAPI { + + static func loadDish(type : EndPoint) -> AnyPublisher { + let request = AF.request(type.url, method: .get) + return API().run(request) + .map(\.value) + .eraseToAnyPublisher() + } +} diff --git a/SideDish/SideDish/Network/EndPoint.swift b/SideDish/SideDish/Network/EndPoint.swift new file mode 100644 index 000000000..791f09631 --- /dev/null +++ b/SideDish/SideDish/Network/EndPoint.swift @@ -0,0 +1,18 @@ +// +// EndPoint.swift +// SideDish +// +// Created by 박혜원 on 2021/04/22. +// + +import Foundation + +enum EndPoint : String, CodingKey { + case main + case soup + case side + + static let baseURL = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/" + var path : String { self.stringValue } + var url : URL { URL(string: EndPoint.baseURL + path)! } +} diff --git a/SideDish/SideDish/Network/LoadError.swift b/SideDish/SideDish/Network/LoadError.swift new file mode 100644 index 000000000..3441383a6 --- /dev/null +++ b/SideDish/SideDish/Network/LoadError.swift @@ -0,0 +1,20 @@ +// +// LoadError.swift +// SideDish +// +// Created by 박혜원 on 2021/04/22. +// + +import Foundation + +enum APIError : Error { + case statusCode + case decoding + case invalidImage + case invalidURL + case other(Error) + + static func map(_ error: Error) -> APIError { + return (error as? APIError) ?? .other(error) + } +} diff --git a/SideDish/SideDish/Network/Response.swift b/SideDish/SideDish/Network/Response.swift new file mode 100644 index 000000000..e99c7101f --- /dev/null +++ b/SideDish/SideDish/Network/Response.swift @@ -0,0 +1,56 @@ +// +// Response.swift +// SideDish +// +// Created by 박혜원 on 2021/04/20. +// + +import Foundation + +struct FoodItem : Codable { + let id : String + let image : String + let alt : String + let delivery : [String]? + let title : String + let description : String + let originalPrice : String? + let discountPrice : String? + let badge : [String]? + + enum CodingKeys : String, CodingKey { + case id = "detail_hash" + case image + case alt + case delivery = "delivery_type" + case title + case description + case originalPrice = "n_price" + case discountPrice = "s_price" + case badge + } +} + +struct CardsResponse : Codable { + let statusCode : Int + let body : [FoodItem] + + func getCards() -> [Card] { + var cards = [Card]() + for item in self.body { + let card = responseToCard(response: item) + cards.append(card) + } + return cards + } + private func responseToCard(response item : FoodItem) -> Card { + let card = Card(id: item.id, + title: item.title, + detail: item.description, + d_price: item.discountPrice, + o_price: item.originalPrice, + url: URL(string: item.image), + badge: item.badge) + return card + } +} diff --git a/SideDish/SideDish/SceneDelegate.swift b/SideDish/SideDish/SceneDelegate.swift new file mode 100644 index 000000000..5163df5c0 --- /dev/null +++ b/SideDish/SideDish/SceneDelegate.swift @@ -0,0 +1,55 @@ +// +// SceneDelegate.swift +// SideDish +// +// Created by 양준혁 on 2021/04/19. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + + // Save changes in the application's managed object context when the application transitions to the background. + (UIApplication.shared.delegate as? AppDelegate)?.saveContext() + } + + +} + diff --git a/SideDish/SideDish/SideDish.xcdatamodeld/.xccurrentversion b/SideDish/SideDish/SideDish.xcdatamodeld/.xccurrentversion new file mode 100644 index 000000000..ae0c8d160 --- /dev/null +++ b/SideDish/SideDish/SideDish.xcdatamodeld/.xccurrentversion @@ -0,0 +1,8 @@ + + + + + _XCCurrentVersionName + SideDish.xcdatamodel + + diff --git a/SideDish/SideDish/SideDish.xcdatamodeld/SideDish.xcdatamodel/contents b/SideDish/SideDish/SideDish.xcdatamodeld/SideDish.xcdatamodel/contents new file mode 100644 index 000000000..50d2514e8 --- /dev/null +++ b/SideDish/SideDish/SideDish.xcdatamodeld/SideDish.xcdatamodel/contents @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SideDish/SideDish/Storyboard/Base.lproj/Main.storyboard b/SideDish/SideDish/Storyboard/Base.lproj/Main.storyboard new file mode 100644 index 000000000..2a8fbfee5 --- /dev/null +++ b/SideDish/SideDish/Storyboard/Base.lproj/Main.storyboard @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SideDish/SideDish/View/CardCell.swift b/SideDish/SideDish/View/CardCell.swift new file mode 100644 index 000000000..e482394c1 --- /dev/null +++ b/SideDish/SideDish/View/CardCell.swift @@ -0,0 +1,97 @@ +// +// CardCell.swift +// SideDish +// +// Created by 양준혁 on 2021/04/19. +// + +import UIKit +import Alamofire + +class CardCell: UICollectionViewCell { + + @IBOutlet weak var thumbnail: UIImageView! + @IBOutlet weak var title: UILabel! + @IBOutlet weak var detail: UILabel! + @IBOutlet weak var discountPrice: UILabel! + @IBOutlet weak var originalPrice: UILabel! + @IBOutlet weak var activityIndicator: UIActivityIndicatorView! + + @IBOutlet weak var badgeView: UIStackView! + + var card : Card? { + didSet { + thumbnail.load(url: card?.imageURL, completion: { + self.activityIndicator.stopAnimating() + }) + title.text = card?.title + detail.text = card?.detail + discountPrice.text = card?.discountPrice?.description + originalPrice.attributedText = NSMutableAttributedString(string: card?.originalPrice?.description ?? "", + attributes: [NSAttributedString.Key.strikethroughStyle: NSUnderlineStyle.single.rawValue]) + guard let badges = card?.badge else { + badgeView.isHidden = true + return + } + + badges.forEach{ badge in + let view = makeBadge(with: badge) + self.badgeView.addArrangedSubview(view) + } + } + } + override func awakeFromNib() { + super.awakeFromNib() + + self.activityIndicator.startAnimating() + configureTitle() + configureDetail() + configureThumbnail() + configureBadgeView() + } + func makeBadge(with name: String) -> UIView { + + let view = UIView(frame: CGRect(x: 0, y: 0, width: 72, height: 25)) + + view.backgroundColor = .white + view.layer.backgroundColor = #colorLiteral(red: 0.5095996261, green: 0.8290402293, blue: 0.1742436588, alpha: 1) + view.layer.cornerRadius = 5 + + let label = UILabel(frame: CGRect(x: 0, y: 0, width: 56, height: 17)) + label.textColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1) + label.font = UIFont(name: "NotoSansKR-Bold", size: 12) + label.text = name + + view.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + label.widthAnchor.constraint(equalToConstant: 56).isActive = true + label.heightAnchor.constraint(equalToConstant: 17).isActive = true + label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + label.topAnchor.constraint(equalTo: view.topAnchor, constant: 4).isActive = true + + return view + } + func configureTitle(){ + self.title.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1) + self.title.font = UIFont(name: "NotoSansKR-Bold", size: 16) + self.title.numberOfLines = 0 + self.title.lineBreakMode = .byWordWrapping + } + func configureDetail(){ + self.detail.textColor = UIColor(red: 0.51, green: 0.51, blue: 0.51, alpha: 1) + self.detail.font = UIFont(name: "NotoSansKR-Regular", size: 14) + } + func configurePrice(){ + self.discountPrice.textColor = UIColor(red: 0.004, green: 0.004, blue: 0.004, alpha: 1) + self.discountPrice.font = UIFont(name: "NotoSansKR-Bold", size: 14) + + self.originalPrice.textColor = UIColor(red: 0.741, green: 0.741, blue: 0.741, alpha: 1) + self.originalPrice.font = UIFont(name: "NotoSansKR-Regular", size: 14) + } + func configureThumbnail(){ + self.thumbnail.layer.cornerRadius = 5 + } + func configureBadgeView(){ + self.badgeView.translatesAutoresizingMaskIntoConstraints = false + } +} diff --git a/SideDish/SideDish/View/CardCell.xib b/SideDish/SideDish/View/CardCell.xib new file mode 100644 index 000000000..49d323452 --- /dev/null +++ b/SideDish/SideDish/View/CardCell.xib @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SideDish/SideDish/View/SectionHeaderReusableView.swift b/SideDish/SideDish/View/SectionHeaderReusableView.swift new file mode 100644 index 000000000..063bd03eb --- /dev/null +++ b/SideDish/SideDish/View/SectionHeaderReusableView.swift @@ -0,0 +1,21 @@ +// +// HeaderView.swift +// SideDish +// +// Created by 박혜원 on 2021/04/19. +// + +import UIKit + +class SectionHeaderReusableView: UICollectionReusableView { + static var reuseIdentifier: String { + return String(describing: SectionHeaderReusableView.self) + } + + @IBOutlet weak var title : UILabel! + + func configure(){ + self.title.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1) + self.title.font = UIFont(name: "NotoSansKR-Bold", size: 22) + } +} diff --git a/SideDish/SideDishTests/APITest.swift b/SideDish/SideDishTests/APITest.swift new file mode 100644 index 000000000..cb22639cb --- /dev/null +++ b/SideDish/SideDishTests/APITest.swift @@ -0,0 +1,18 @@ +// +// APITest.swift +// SideDishTests +// +// Created by 박혜원 on 2021/04/22. +// + +import XCTest +@testable import SideDish + +class APITest: XCTestCase { + + func testLoadMainDish(){ + + NSLog(CardAPI.loadDish(type: .main).description) + } + +} diff --git a/SideDish/SideDishTests/Info.plist b/SideDish/SideDishTests/Info.plist new file mode 100644 index 000000000..64d65ca49 --- /dev/null +++ b/SideDish/SideDishTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/SideDish/SideDishTests/SideDishTests.swift b/SideDish/SideDishTests/SideDishTests.swift new file mode 100644 index 000000000..128366c87 --- /dev/null +++ b/SideDish/SideDishTests/SideDishTests.swift @@ -0,0 +1,33 @@ +// +// SideDishTests.swift +// SideDishTests +// +// Created by 양준혁 on 2021/04/19. +// + +import XCTest +@testable import SideDish + +class SideDishTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/SideDish/SideDishUITests/Info.plist b/SideDish/SideDishUITests/Info.plist new file mode 100644 index 000000000..64d65ca49 --- /dev/null +++ b/SideDish/SideDishUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/SideDish/SideDishUITests/SideDishUITests.swift b/SideDish/SideDishUITests/SideDishUITests.swift new file mode 100644 index 000000000..b048130d6 --- /dev/null +++ b/SideDish/SideDishUITests/SideDishUITests.swift @@ -0,0 +1,42 @@ +// +// SideDishUITests.swift +// SideDishUITests +// +// Created by 양준혁 on 2021/04/19. +// + +import XCTest + +class SideDishUITests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +}