From 77fa7c19370c7c4adab3828ab3b0254a1e15feb0 Mon Sep 17 00:00:00 2001 From: okstring Date: Mon, 26 Apr 2021 16:57:58 +0900 Subject: [PATCH 01/20] =?UTF-8?q?Modify:=20Section=20=E1=84=87=E1=85=A7?= =?UTF-8?q?=E1=86=AF=E1=84=85=E1=85=A9=20=E1=84=87=E1=85=AE=E1=86=AF?= =?UTF-8?q?=E1=84=85=E1=85=A5=E1=84=8B=E1=85=A9=E1=84=80=E1=85=A6=E1=84=81?= =?UTF-8?q?=E1=85=B3=E1=86=B7=20=E1=84=89=E1=85=AE=E1=84=8C=E1=85=A5?= =?UTF-8?q?=E1=86=BC,=20Header=20Toast=20=E1=84=80=E1=85=AE=E1=84=8C?= =?UTF-8?q?=E1=85=A9=20=E1=84=89=E1=85=AE=E1=84=8C=E1=85=A5=E1=86=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sidedish/Pods/Pods.xcodeproj/project.pbxproj | 27 +++---- .../xcschemes/Alamofire.xcscheme | 24 +++--- .../xcschemes/Kingfisher.xcscheme | 24 +++--- .../xcschemes/Pods-Sidedish.xcscheme | 2 +- .../xcschemes/Toaster.xcscheme | 24 +++--- Sidedish/Sidedish.xcodeproj/project.pbxproj | 41 +++++----- .../xcdebugger/Breakpoints_v2.xcbkptlist | 2 +- Sidedish/Sidedish/Entity/Enum/Category.swift | 30 ++++++++ Sidedish/Sidedish/Entity/SidedishItem.swift | 2 +- .../View/HeaderCollectionReusableView.swift | 22 ++++++ Sidedish/Sidedish/ViewController.swift | 74 ++++++++++--------- .../Sidedish/ViewModel/ItemViewModel.swift | 13 ++-- 12 files changed, 170 insertions(+), 115 deletions(-) create mode 100644 Sidedish/Sidedish/Entity/Enum/Category.swift diff --git a/Sidedish/Pods/Pods.xcodeproj/project.pbxproj b/Sidedish/Pods/Pods.xcodeproj/project.pbxproj index 09c5e894b..29f07f51c 100644 --- a/Sidedish/Pods/Pods.xcodeproj/project.pbxproj +++ b/Sidedish/Pods/Pods.xcodeproj/project.pbxproj @@ -193,7 +193,7 @@ 5546AC3CDDAF7DC0CFA3796AE0DA8677 /* KingfisherOptionsInfo.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KingfisherOptionsInfo.swift; path = Sources/General/KingfisherOptionsInfo.swift; sourceTree = ""; }; 5A18CDCBC3FBFBFAC9A819B84F9CFB65 /* Alamofire.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.debug.xcconfig; sourceTree = ""; }; 5BEB8A00C858140301ECFBB90CBB4B68 /* DispatchQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Alamofire.swift"; path = "Source/DispatchQueue+Alamofire.swift"; sourceTree = ""; }; - 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Alamofire.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 61CF2BA135DF65D19254FAB23927CE05 /* Toaster-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Toaster-Info.plist"; sourceTree = ""; }; 62FAA0A50F09BFD404E9D350559D4E8F /* ParameterEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoder.swift; path = Source/ParameterEncoder.swift; sourceTree = ""; }; 684C336F2524AEFA1191AD5F30B0DF0C /* Pods-Sidedish-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Sidedish-Info.plist"; sourceTree = ""; }; @@ -223,7 +223,7 @@ 997261987EDE5BE1A2280361D7C95E71 /* Alamofire-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Alamofire-Info.plist"; sourceTree = ""; }; 9BC532BC44D73F9DE3F0EF44AC20DC13 /* GIFAnimatedImage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GIFAnimatedImage.swift; path = Sources/Image/GIFAnimatedImage.swift; sourceTree = ""; }; 9C4F6D1A3FD12E4C53D9709D96A9FBB7 /* MultipartUpload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartUpload.swift; path = Source/MultipartUpload.swift; sourceTree = ""; }; - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 9E3A56BADDEDBB209293D988CFD01216 /* RequestTaskMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestTaskMap.swift; path = Source/RequestTaskMap.swift; sourceTree = ""; }; 9E42319F10ABA3D99672EC9EF9819E39 /* Pods-Sidedish.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Sidedish.modulemap"; sourceTree = ""; }; A040238BA51D7DF819BB51F69A89E1A1 /* ServerTrustEvaluation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerTrustEvaluation.swift; path = Source/ServerTrustEvaluation.swift; sourceTree = ""; }; @@ -243,13 +243,13 @@ B771D69358C190D0AB2DA3E6D9EE6519 /* ImageDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImageDataProvider.swift; path = Sources/General/ImageSource/ImageDataProvider.swift; sourceTree = ""; }; BB94DF5CBF98397E51578A800B43E1EF /* DiskStorage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DiskStorage.swift; path = Sources/Cache/DiskStorage.swift; sourceTree = ""; }; BC20583584018C67D45C798EFD4AAD84 /* Source.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Source.swift; path = Sources/General/ImageSource/Source.swift; sourceTree = ""; }; - BD810337F4A305D60D9250A197AA1EF1 /* Toaster.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Toaster.framework; path = Toaster.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BD810337F4A305D60D9250A197AA1EF1 /* Toaster.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Toaster.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C033C73405484F32AEF29BBD00E7B5E7 /* ImageBinder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImageBinder.swift; path = Sources/SwiftUI/ImageBinder.swift; sourceTree = ""; }; C0D58798A502D2E85339C27E6EF936EA /* Pods-Sidedish-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Sidedish-dummy.m"; sourceTree = ""; }; C39A1975FAC8DD8A0B77DA0175884F60 /* Alamofire-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Alamofire-dummy.m"; sourceTree = ""; }; C39FB42703628A574936FED6212CF8AD /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = Source/Combine.swift; sourceTree = ""; }; C3C4379B6A7CFEABF7AC18F1AA02E244 /* Session.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Session.swift; path = Source/Session.swift; sourceTree = ""; }; - C3F44C782D64D7EB20B61CE3844EBFAD /* Kingfisher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Kingfisher.framework; path = Kingfisher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C3F44C782D64D7EB20B61CE3844EBFAD /* Kingfisher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kingfisher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C586303DC54D2EF1D453459E4B613B14 /* Toaster-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Toaster-prefix.pch"; sourceTree = ""; }; C610AAF08375AA97F81F6A47FA83FA21 /* SessionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionDelegate.swift; path = Source/SessionDelegate.swift; sourceTree = ""; }; C763355C5B15DDD66703826D17E4FCF7 /* Validation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validation.swift; path = Source/Validation.swift; sourceTree = ""; }; @@ -279,7 +279,7 @@ F7CA3B74E19BDE99939A4D425AE39974 /* URLConvertible+URLRequestConvertible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLConvertible+URLRequestConvertible.swift"; path = "Source/URLConvertible+URLRequestConvertible.swift"; sourceTree = ""; }; F7E967A235964DEBAA8A7FFE7531915B /* Kingfisher-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Kingfisher-Info.plist"; sourceTree = ""; }; FA2E1604B6CE42044FC7EB9980CB821D /* RedirectHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RedirectHandler.swift; path = Source/RedirectHandler.swift; sourceTree = ""; }; - FC47262A97C2A5D7D86D84DE91EB7EB8 /* Pods_Sidedish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Sidedish.framework; path = "Pods-Sidedish.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + FC47262A97C2A5D7D86D84DE91EB7EB8 /* Pods_Sidedish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sidedish.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FD00DB24D8F615B552494FE0AA0EC7B0 /* Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = Source/Alamofire.swift; sourceTree = ""; }; FDE3F6EFAAE97D0E7AAC53E66679D94C /* String+MD5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+MD5.swift"; path = "Sources/Utility/String+MD5.swift"; sourceTree = ""; }; FE0FE30335745175CBE81E8E748272FE /* Alamofire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.release.xcconfig; sourceTree = ""; }; @@ -368,7 +368,6 @@ C763355C5B15DDD66703826D17E4FCF7 /* Validation.swift */, AA904C0E360C01CF6A64CD9C8EEF9D36 /* Support Files */, ); - name = Alamofire; path = Alamofire; sourceTree = ""; }; @@ -424,7 +423,6 @@ 2109DAFA24975C11DC1DA375998FB3AF /* UIApplication+Load.swift */, E7DBEFDE50EE6311046FF21D3EFF236F /* Support Files */, ); - name = Toaster; path = Toaster; sourceTree = ""; }; @@ -570,7 +568,6 @@ EE430722E5EE22546D304DE46B09BE4D /* WKInterfaceImage+Kingfisher.swift */, EE4FEAB3A75C042BC4AE38529B3AD491 /* Support Files */, ); - name = Kingfisher; path = Kingfisher; sourceTree = ""; }; @@ -695,7 +692,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1100; + LastUpgradeCheck = 1240; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 10.0"; @@ -917,7 +914,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Toaster/Toaster-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Toaster/Toaster-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -952,7 +949,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -987,7 +984,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Kingfisher/Kingfisher-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Kingfisher/Kingfisher-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1151,7 +1148,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Kingfisher/Kingfisher-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Kingfisher/Kingfisher-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1186,7 +1183,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1258,7 +1255,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Toaster/Toaster-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Toaster/Toaster-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Alamofire.xcscheme b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Alamofire.xcscheme index bc06c13ed..120775c60 100644 --- a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Alamofire.xcscheme +++ b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Alamofire.xcscheme @@ -1,17 +1,17 @@ + buildForArchiving = "YES" + buildForAnalyzing = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + debugDocumentVersioning = "YES"> diff --git a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Kingfisher.xcscheme b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Kingfisher.xcscheme index 32d098a4a..0074170f7 100644 --- a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Kingfisher.xcscheme +++ b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Kingfisher.xcscheme @@ -1,17 +1,17 @@ + buildForArchiving = "YES" + buildForAnalyzing = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + debugDocumentVersioning = "YES"> diff --git a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Pods-Sidedish.xcscheme b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Pods-Sidedish.xcscheme index cef84a694..f28bc084a 100644 --- a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Pods-Sidedish.xcscheme +++ b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/issac.xcuserdatad/xcschemes/Pods-Sidedish.xcscheme @@ -1,6 +1,6 @@ + buildForArchiving = "YES" + buildForAnalyzing = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES"> + + - - + debugDocumentVersioning = "YES"> diff --git a/Sidedish/Sidedish.xcodeproj/project.pbxproj b/Sidedish/Sidedish.xcodeproj/project.pbxproj index e837f38cd..0578f7f93 100644 --- a/Sidedish/Sidedish.xcodeproj/project.pbxproj +++ b/Sidedish/Sidedish.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 1C6FD9F8FE4DF3D612C7FC78 /* Pods_Sidedish.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69AD776A2215C9567BE9325D /* Pods_Sidedish.framework */; }; + 222E3DB32636936600CB8330 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222E3DB22636936600CB8330 /* Category.swift */; }; 2240D5AC262D74890077EF4D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2240D5AB262D74890077EF4D /* DetailViewController.swift */; }; 2240D5B0262D7E500077EF4D /* ItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2240D5AF262D7E500077EF4D /* ItemViewModel.swift */; }; 22418742262D4D8300AC14C7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22418741262D4D8300AC14C7 /* AppDelegate.swift */; }; @@ -18,18 +18,19 @@ 2241874E262D4D8600AC14C7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2241874C262D4D8600AC14C7 /* LaunchScreen.storyboard */; }; 22418761262D5C8400AC14C7 /* HeaderCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22418760262D5C8400AC14C7 /* HeaderCollectionReusableView.swift */; }; 22418771262D6A5A00AC14C7 /* SidedishItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22418770262D6A5A00AC14C7 /* SidedishItem.swift */; }; - 22418774262D6B3400AC14C7 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22418773262D6B3400AC14C7 /* Category.swift */; }; 2245D88E262D929600E0B637 /* SidedishNetworkCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2245D88D262D929600E0B637 /* SidedishNetworkCenter.swift */; }; 2260DDDA262D960E002DF3E7 /* SidedishProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2260DDD9262D960E002DF3E7 /* SidedishProcessing.swift */; }; 2291A1A926326FD6007A1B72 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2291A1A826326FD6007A1B72 /* Badge.swift */; }; 22BBE64E262D9FCC001D06D5 /* SidedishOfCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */; }; 22D5024A2633049700325C5F /* String+NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22D502492633049700325C5F /* String+NSAttributedString.swift */; }; 22EBA5662633B332009611CB /* HeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22EBA5652633B332009611CB /* HeaderViewModel.swift */; }; + A46CDD6D47430A384FEB7271 /* Pods_Sidedish.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2266576CDB07714024C22C84 /* Pods_Sidedish.framework */; }; D06C739626310CD3002404A3 /* BadgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06C739526310CD3002404A3 /* BadgeLabel.swift */; }; D08A5398262D587700DD1CBE /* ItemCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 222E3DB22636936600CB8330 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; }; 2240D5AB262D74890077EF4D /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 2240D5AF262D7E500077EF4D /* ItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemViewModel.swift; sourceTree = ""; }; 2241873E262D4D8300AC14C7 /* Sidedish.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sidedish.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -42,18 +43,17 @@ 2241874F262D4D8600AC14C7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22418760262D5C8400AC14C7 /* HeaderCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderCollectionReusableView.swift; sourceTree = ""; }; 22418770262D6A5A00AC14C7 /* SidedishItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishItem.swift; sourceTree = ""; }; - 22418773262D6B3400AC14C7 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; }; 2245D88D262D929600E0B637 /* SidedishNetworkCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishNetworkCenter.swift; sourceTree = ""; }; 2260DDD9262D960E002DF3E7 /* SidedishProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishProcessing.swift; sourceTree = ""; }; + 2266576CDB07714024C22C84 /* Pods_Sidedish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sidedish.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2291A1A826326FD6007A1B72 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = ""; }; 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishOfCategory.swift; sourceTree = ""; }; 22D502492633049700325C5F /* String+NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+NSAttributedString.swift"; sourceTree = ""; }; 22EBA5652633B332009611CB /* HeaderViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderViewModel.swift; sourceTree = ""; }; - 499E51924357C5AFEF94978D /* Pods-Sidedish.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.release.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.release.xcconfig"; sourceTree = ""; }; - 69AD776A2215C9567BE9325D /* Pods_Sidedish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sidedish.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 71EC35DD2BAA44FFBB2A183D /* Pods-Sidedish.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.debug.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.debug.xcconfig"; sourceTree = ""; }; D06C739526310CD3002404A3 /* BadgeLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeLabel.swift; sourceTree = ""; }; D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCollectionViewCell.swift; sourceTree = ""; }; - F6FF97B8F04F0E1EF7926092 /* Pods-Sidedish.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.debug.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.debug.xcconfig"; sourceTree = ""; }; + E7B0F586A26D135247BB28E9 /* Pods-Sidedish.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.release.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,7 +61,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1C6FD9F8FE4DF3D612C7FC78 /* Pods_Sidedish.framework in Frameworks */, + A46CDD6D47430A384FEB7271 /* Pods_Sidedish.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,8 +71,8 @@ 1D84EDAD3656EE6C148133E1 /* Pods */ = { isa = PBXGroup; children = ( - F6FF97B8F04F0E1EF7926092 /* Pods-Sidedish.debug.xcconfig */, - 499E51924357C5AFEF94978D /* Pods-Sidedish.release.xcconfig */, + 71EC35DD2BAA44FFBB2A183D /* Pods-Sidedish.debug.xcconfig */, + E7B0F586A26D135247BB28E9 /* Pods-Sidedish.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -103,7 +103,7 @@ 22418740262D4D8300AC14C7 /* Sidedish */, 2241873F262D4D8300AC14C7 /* Products */, 1D84EDAD3656EE6C148133E1 /* Pods */, - C86369EE41D09B45D38A333E /* Frameworks */, + E82A359D5367162E8BD6F247 /* Frameworks */, ); sourceTree = ""; }; @@ -140,7 +140,6 @@ children = ( 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */, 22418770262D6A5A00AC14C7 /* SidedishItem.swift */, - 22418773262D6B3400AC14C7 /* Category.swift */, 2291A1AB26326FDB007A1B72 /* Enum */, ); path = Entity; @@ -166,14 +165,15 @@ isa = PBXGroup; children = ( 2291A1A826326FD6007A1B72 /* Badge.swift */, + 222E3DB22636936600CB8330 /* Category.swift */, ); path = Enum; sourceTree = ""; }; - C86369EE41D09B45D38A333E /* Frameworks */ = { + E82A359D5367162E8BD6F247 /* Frameworks */ = { isa = PBXGroup; children = ( - 69AD776A2215C9567BE9325D /* Pods_Sidedish.framework */, + 2266576CDB07714024C22C84 /* Pods_Sidedish.framework */, ); name = Frameworks; sourceTree = ""; @@ -185,11 +185,11 @@ isa = PBXNativeTarget; buildConfigurationList = 22418752262D4D8600AC14C7 /* Build configuration list for PBXNativeTarget "Sidedish" */; buildPhases = ( - 99EF1A974FC5FDCCD4C181F2 /* [CP] Check Pods Manifest.lock */, + D56790A355E7FA67B504169D /* [CP] Check Pods Manifest.lock */, 2241873A262D4D8300AC14C7 /* Sources */, 2241873B262D4D8300AC14C7 /* Frameworks */, 2241873C262D4D8300AC14C7 /* Resources */, - 51DCBCA7A1C26592512CB930 /* [CP] Embed Pods Frameworks */, + 022FB5EAFC5AD6AF8F5F1709 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -246,7 +246,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 51DCBCA7A1C26592512CB930 /* [CP] Embed Pods Frameworks */ = { + 022FB5EAFC5AD6AF8F5F1709 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -263,7 +263,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Sidedish/Pods-Sidedish-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 99EF1A974FC5FDCCD4C181F2 /* [CP] Check Pods Manifest.lock */ = { + D56790A355E7FA67B504169D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -303,8 +303,8 @@ 22418761262D5C8400AC14C7 /* HeaderCollectionReusableView.swift in Sources */, 2240D5B0262D7E500077EF4D /* ItemViewModel.swift in Sources */, 2245D88E262D929600E0B637 /* SidedishNetworkCenter.swift in Sources */, + 222E3DB32636936600CB8330 /* Category.swift in Sources */, 22418744262D4D8300AC14C7 /* SceneDelegate.swift in Sources */, - 22418774262D6B3400AC14C7 /* Category.swift in Sources */, 2240D5AC262D74890077EF4D /* DetailViewController.swift in Sources */, 22BBE64E262D9FCC001D06D5 /* SidedishOfCategory.swift in Sources */, 2260DDDA262D960E002DF3E7 /* SidedishProcessing.swift in Sources */, @@ -451,7 +451,7 @@ }; 22418753262D4D8600AC14C7 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F6FF97B8F04F0E1EF7926092 /* Pods-Sidedish.debug.xcconfig */; + baseConfigurationReference = 71EC35DD2BAA44FFBB2A183D /* Pods-Sidedish.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -463,6 +463,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = kr.maylily.Sidedish; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_COMPILATION_MODE = singlefile; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -470,7 +471,7 @@ }; 22418754262D4D8600AC14C7 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 499E51924357C5AFEF94978D /* Pods-Sidedish.release.xcconfig */; + baseConfigurationReference = E7B0F586A26D135247BB28E9 /* Pods-Sidedish.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; diff --git a/Sidedish/Sidedish.xcworkspace/xcuserdata/issac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Sidedish/Sidedish.xcworkspace/xcuserdata/issac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 4e2ed4a8b..ed32b4376 100644 --- a/Sidedish/Sidedish.xcworkspace/xcuserdata/issac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Sidedish/Sidedish.xcworkspace/xcuserdata/issac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -1,6 +1,6 @@ diff --git a/Sidedish/Sidedish/Entity/Enum/Category.swift b/Sidedish/Sidedish/Entity/Enum/Category.swift new file mode 100644 index 000000000..8218a8868 --- /dev/null +++ b/Sidedish/Sidedish/Entity/Enum/Category.swift @@ -0,0 +1,30 @@ +// +// Category.swift +// Sidedish +// +// Created by Issac on 2021/04/26. +// + +import Foundation + +enum Category: Int, CustomStringConvertible, CaseIterable { + case main = 0 + case soup = 1 + case side = 2 + + var description: String { + switch self { + case .main: return "main" + case .soup: return "soup" + case .side: return "side" + } + } + + var index: Int { + switch self { + case .main: return 0 + case .soup: return 1 + case .side: return 2 + } + } +} diff --git a/Sidedish/Sidedish/Entity/SidedishItem.swift b/Sidedish/Sidedish/Entity/SidedishItem.swift index 00b71a27f..6c2ca5133 100644 --- a/Sidedish/Sidedish/Entity/SidedishItem.swift +++ b/Sidedish/Sidedish/Entity/SidedishItem.swift @@ -21,7 +21,7 @@ struct SidedishItem: Codable { enum CodingKeys: String, CodingKey { case detailHash = "detail_hash" - case imageURL + case imageURL = "image" case alt case deliveryType = "delivery_type" case title diff --git a/Sidedish/Sidedish/View/HeaderCollectionReusableView.swift b/Sidedish/Sidedish/View/HeaderCollectionReusableView.swift index 2b6c1feff..1399b2024 100644 --- a/Sidedish/Sidedish/View/HeaderCollectionReusableView.swift +++ b/Sidedish/Sidedish/View/HeaderCollectionReusableView.swift @@ -7,10 +7,32 @@ import UIKit +protocol HeaderClickable: class { + func didClickedHeader(attributedQuote: NSAttributedString) +} + class HeaderCollectionReusableView: UICollectionReusableView { static let identifier = "collectionViewHeader" + weak var delegate: HeaderClickable? + @IBOutlet weak var title: UILabel! @IBOutlet weak var countLabel: UILabel! + override init(frame: CGRect) { + super.init(frame: frame) + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapped)) + self.addGestureRecognizer(tapGesture) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapped)) + self.addGestureRecognizer(tapGesture) + } + + @objc func didTapped() { + let attributedQuote = "\(title.text ?? "")\n\(countLabel.text ?? "")".attributedStringOfFontSize(of: 16) + self.delegate?.didClickedHeader(attributedQuote: attributedQuote) + } } diff --git a/Sidedish/Sidedish/ViewController.swift b/Sidedish/Sidedish/ViewController.swift index f981918cf..e433c295c 100644 --- a/Sidedish/Sidedish/ViewController.swift +++ b/Sidedish/Sidedish/ViewController.swift @@ -20,30 +20,13 @@ class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - let networking = SidedishNetworkCenter() let sidedishProcessing = SidedishProcessing(networkable: networking) self.itemViewModel = ItemViewModel(sidedishProcessable: sidedishProcessing) self.headerViewModel = HeaderViewModel() self.bind() - - self.itemViewModel.errorHandler = { error in - Toast(text: error).show() - } - - self.itemViewModel.imageReloadHandler = { index in - self.collectionView.reloadItems(at: [IndexPath(index: index)]) - } - - self.headerViewActionHander = { - let title = self.headerViewModel.titles[0] - let countText = "\(self.itemViewModel.items.count)개 상품이 등록되어 있습니다." - let attributedQuote = "\(title)\n\(countText)".attributedStringOfFontSize(of: 16) - Toast(attributedText: attributedQuote).show() - } - - self.itemViewModel.fetchItems() + self.loadItems() } override func viewWillAppear(_ animated: Bool) { @@ -51,28 +34,47 @@ class ViewController: UIViewController { self.navigationController?.isNavigationBarHidden = true } + private func loadItems() { + Category.allCases.forEach { (category) in + self.itemViewModel.fetchItems(of: category) + } + } + private func bind() { - self.itemViewModel.$items - .receive(on: DispatchQueue.main) - .sink { [weak self] _ in - self?.collectionView.reloadSections(IndexSet(integer: 0)) - }.store(in: &fetchItemSubscription) + self.itemViewModel.reloadHandler = { category in + DispatchQueue.main.async { + self.collectionView.reloadSections(IndexSet(integer: category.index)) + } + } + + self.itemViewModel.errorHandler = { error in + Toast(text: error).show() + } + + self.itemViewModel.imageReloadHandler = { index in + self.collectionView.reloadItems(at: [IndexPath(index: index)]) + } } } extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return self.itemViewModel.items.count + guard let category = Category.init(rawValue: section) else { return 0 } + guard let item = self.itemViewModel.items[category.description] else { return 0 } + return item.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ItemCollectionViewCell.identifier, for: indexPath) as? ItemCollectionViewCell else { return ItemCollectionViewCell() } - let item = self.itemViewModel.items[indexPath.row] + + guard let category = Category.init(rawValue: indexPath.section) else { return cell } + guard let item = self.itemViewModel.items[category.description]?[indexPath.row] else { return cell } let badge = handleBadge(badge: item.badge) cell.configure(model: item, nPrice: item.nPrice, badge: badge) - guard let data = self.itemViewModel.items[indexPath.row].imageData else { return cell } + guard let data = item.imageData else { return cell } cell.configure(data: data) return cell @@ -86,16 +88,16 @@ extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: HeaderCollectionReusableView.identifier, for: indexPath) as! HeaderCollectionReusableView - - let tapRecognizer = UITapGestureRecognizer(target: self, - action: #selector(makingHeaderToast(_:))) - - header.addGestureRecognizer(tapRecognizer) + header.delegate = self + guard let category = Category(rawValue: indexPath.section) else { return header } + guard let items = self.itemViewModel.items[category.description] else { return header } + header.title.text = self.headerViewModel.titles[indexPath.section] + header.countLabel.text = "\(items.count)개 상품이 등록되어 있습니다" return header } - @objc func makingHeaderToast(_ sender: UITapGestureRecognizer) { - self.headerViewActionHander?() + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + print(indexPath.row, indexPath.section) } } @@ -105,6 +107,12 @@ extension ViewController: UICollectionViewDelegateFlowLayout { } } +extension ViewController: HeaderClickable { + func didClickedHeader(attributedQuote: NSAttributedString) { + Toast(attributedText: attributedQuote).show() + } +} + extension ViewController { func handleBadge(badge: [String]?) -> [Bool] { var isHiddenBadges = [true, true] diff --git a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift index 430eaefb6..d4ec0de22 100644 --- a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift +++ b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift @@ -8,23 +8,26 @@ import Foundation class ItemViewModel { - @Published var items: [SidedishItem] + var items: Dictionary var imageReloadHandler: ((Int) -> ())? var errorHandler: ((String) -> ())? + var reloadHandler: ((Category) -> ())? var sidedishProcessing: SidedishProcessable init(sidedishProcessable: SidedishProcessable) { - self.items = [SidedishItem]() + self.items = Dictionary() self.sidedishProcessing = sidedishProcessable } - func fetchItems() { - let url = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/main" + func fetchItems(of category: Category) { + let url = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/\(category)" self.sidedishProcessing.getItems(url: url) { [weak self] (result) in switch result { case .success(let sidedishItems): guard let strongSelf = self else { return } - strongSelf.items = strongSelf.setOriginalPrice(items: sidedishItems) + let items = strongSelf.setOriginalPrice(items: sidedishItems) + strongSelf.items[category.description, default: [SidedishItem]()] = items + strongSelf.reloadHandler?(category) case .failure(let error): #if DEBUG NSLog(error.localizedDescription) From 8391a8dfff8897903cc2e40eeb29634efd89f215 Mon Sep 17 00:00:00 2001 From: okstring Date: Mon, 26 Apr 2021 16:58:31 +0900 Subject: [PATCH 02/20] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcschemes/xcschememanagement.plist | 29 ------------------ .../UserInterfaceState.xcuserstate | Bin 119645 -> 0 bytes Sidedish/Sidedish/Entity/Category.swift | 20 ------------ 3 files changed, 49 deletions(-) delete mode 100644 Sidedish/Pods/Pods.xcodeproj/xcuserdata/ador.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 Sidedish/Sidedish.xcworkspace/xcuserdata/ador.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 Sidedish/Sidedish/Entity/Category.swift diff --git a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/ador.xcuserdatad/xcschemes/xcschememanagement.plist b/Sidedish/Pods/Pods.xcodeproj/xcuserdata/ador.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 04932d5b2..000000000 --- a/Sidedish/Pods/Pods.xcodeproj/xcuserdata/ador.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - SchemeUserState - - Alamofire.xcscheme_^#shared#^_ - - orderHint - 4 - - Kingfisher.xcscheme_^#shared#^_ - - orderHint - 0 - - Pods-Sidedish.xcscheme_^#shared#^_ - - orderHint - 1 - - Toaster.xcscheme_^#shared#^_ - - orderHint - 3 - - - - diff --git a/Sidedish/Sidedish.xcworkspace/xcuserdata/ador.xcuserdatad/UserInterfaceState.xcuserstate b/Sidedish/Sidedish.xcworkspace/xcuserdata/ador.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 4154b7750d854923535b835faf2d09b13407f0d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119645 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 S{>lFI|NH;{|G%M5S^f_NqaHy3 diff --git a/Sidedish/Sidedish/Entity/Category.swift b/Sidedish/Sidedish/Entity/Category.swift deleted file mode 100644 index d2b377f97..000000000 --- a/Sidedish/Sidedish/Entity/Category.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Category.swift -// Sidedish -// -// Created by Issac on 2021/04/19. -// - -import Foundation - -struct Category: Codable { - var categoryId: String - var name: String - var item: [SidedishItem] - - enum Category: String, CodingKey { - case categoryId = "category_id" - case name - case item - } -} From 4abf57fae5b982b404f9c50d7e2933247fb4acb0 Mon Sep 17 00:00:00 2001 From: lena Date: Tue, 27 Apr 2021 11:25:15 +0900 Subject: [PATCH 03/20] Add Detail Scroll View --- Sidedish/Sidedish/DetailViewController.swift | 9 ++- .../Sidedish/View/Base.lproj/Main.storyboard | 65 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index 519ca8d00..9c91feb9e 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -9,9 +9,16 @@ import UIKit class DetailViewController: UIViewController { + @IBOutlet weak var detailImages: UIStackView! + override func viewDidLoad() { super.viewDidLoad() - + + // 상세이미지 추가 + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true + detailImages.addArrangedSubview(imageView) } override func viewWillAppear(_ animated: Bool) { diff --git a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard index 104ad7a3c..500d9d8e2 100644 --- a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard +++ b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard @@ -193,15 +193,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - + @@ -234,8 +292,5 @@ - - - From 0eb6846e3eb5c27e9b449db34bc3988470678741 Mon Sep 17 00:00:00 2001 From: okstring Date: Tue, 27 Apr 2021 11:29:32 +0900 Subject: [PATCH 04/20] Add detail network --- Sidedish/Sidedish.xcodeproj/project.pbxproj | 8 +++ Sidedish/Sidedish/DetailViewController.swift | 28 +++++++- Sidedish/Sidedish/Entity/Detail.swift | 12 ++++ Sidedish/Sidedish/Entity/DetailItem.swift | 51 ++++++++++++++ .../Repository/SidedishNetworkCenter.swift | 41 +++++++++++ .../Sidedish/UseCase/SidedishProcessing.swift | 12 ++++ .../Sidedish/View/Base.lproj/Main.storyboard | 69 +++++++------------ Sidedish/Sidedish/ViewController.swift | 15 ++++ .../Sidedish/ViewModel/ItemViewModel.swift | 20 ++++++ 9 files changed, 208 insertions(+), 48 deletions(-) create mode 100644 Sidedish/Sidedish/Entity/Detail.swift create mode 100644 Sidedish/Sidedish/Entity/DetailItem.swift diff --git a/Sidedish/Sidedish.xcodeproj/project.pbxproj b/Sidedish/Sidedish.xcodeproj/project.pbxproj index 0578f7f93..7677e2e5f 100644 --- a/Sidedish/Sidedish.xcodeproj/project.pbxproj +++ b/Sidedish/Sidedish.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 22418771262D6A5A00AC14C7 /* SidedishItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22418770262D6A5A00AC14C7 /* SidedishItem.swift */; }; 2245D88E262D929600E0B637 /* SidedishNetworkCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2245D88D262D929600E0B637 /* SidedishNetworkCenter.swift */; }; 2260DDDA262D960E002DF3E7 /* SidedishProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2260DDD9262D960E002DF3E7 /* SidedishProcessing.swift */; }; + 228295BC263780B000BBDACD /* DetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228295BB263780B000BBDACD /* DetailItem.swift */; }; + 228295C32637813C00BBDACD /* Detail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228295C22637813C00BBDACD /* Detail.swift */; }; 2291A1A926326FD6007A1B72 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2291A1A826326FD6007A1B72 /* Badge.swift */; }; 22BBE64E262D9FCC001D06D5 /* SidedishOfCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */; }; 22D5024A2633049700325C5F /* String+NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22D502492633049700325C5F /* String+NSAttributedString.swift */; }; @@ -46,6 +48,8 @@ 2245D88D262D929600E0B637 /* SidedishNetworkCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishNetworkCenter.swift; sourceTree = ""; }; 2260DDD9262D960E002DF3E7 /* SidedishProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishProcessing.swift; sourceTree = ""; }; 2266576CDB07714024C22C84 /* Pods_Sidedish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sidedish.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 228295BB263780B000BBDACD /* DetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailItem.swift; sourceTree = ""; }; + 228295C22637813C00BBDACD /* Detail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Detail.swift; sourceTree = ""; }; 2291A1A826326FD6007A1B72 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = ""; }; 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidedishOfCategory.swift; sourceTree = ""; }; 22D502492633049700325C5F /* String+NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+NSAttributedString.swift"; sourceTree = ""; }; @@ -140,6 +144,8 @@ children = ( 22BBE64D262D9FCC001D06D5 /* SidedishOfCategory.swift */, 22418770262D6A5A00AC14C7 /* SidedishItem.swift */, + 228295BB263780B000BBDACD /* DetailItem.swift */, + 228295C22637813C00BBDACD /* Detail.swift */, 2291A1AB26326FDB007A1B72 /* Enum */, ); path = Entity; @@ -294,6 +300,7 @@ files = ( D06C739626310CD3002404A3 /* BadgeLabel.swift in Sources */, 22D5024A2633049700325C5F /* String+NSAttributedString.swift in Sources */, + 228295C32637813C00BBDACD /* Detail.swift in Sources */, 2291A1A926326FD6007A1B72 /* Badge.swift in Sources */, 22418746262D4D8300AC14C7 /* ViewController.swift in Sources */, 22EBA5662633B332009611CB /* HeaderViewModel.swift in Sources */, @@ -302,6 +309,7 @@ 22418771262D6A5A00AC14C7 /* SidedishItem.swift in Sources */, 22418761262D5C8400AC14C7 /* HeaderCollectionReusableView.swift in Sources */, 2240D5B0262D7E500077EF4D /* ItemViewModel.swift in Sources */, + 228295BC263780B000BBDACD /* DetailItem.swift in Sources */, 2245D88E262D929600E0B637 /* SidedishNetworkCenter.swift in Sources */, 222E3DB32636936600CB8330 /* Category.swift in Sources */, 22418744262D4D8300AC14C7 /* SceneDelegate.swift in Sources */, diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index 9c91feb9e..f8875a7aa 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -8,9 +8,11 @@ import UIKit class DetailViewController: UIViewController { - @IBOutlet weak var detailImages: UIStackView! - + @IBOutlet weak var imageScrollView: UIScrollView! + @IBOutlet weak var contentView: UIView! + var itemViewModel: ItemViewModel! + override func viewDidLoad() { super.viewDidLoad() @@ -19,10 +21,30 @@ class DetailViewController: UIViewController { imageView.contentMode = .scaleAspectFit imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true detailImages.addArrangedSubview(imageView) + + itemViewModel.detailHandler = { + print(self.itemViewModel.currentDetail.detailSectionData) + } + } + +private func setImage() { + let currentDetailItem = self.itemViewModel.currentDetail + self.imageScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) + self.imageScrollView.contentSize = CGSize(width: self.view.frame.width * CGFloat((currentDetailItem.thumbImagesData?.count ?? 0 + 1) ?? 0), height: self.view.frame.width) + self.imageScrollView.isPagingEnabled = true + + for index in 0..<(currentDetailItem.thumbImagesData?.count ?? 0) + 1{ + } - override func viewWillAppear(_ animated: Bool) { +} + +override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.isNavigationBarHidden = false } + + func setImageScrollView() { + self.imageScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) + } } diff --git a/Sidedish/Sidedish/Entity/Detail.swift b/Sidedish/Sidedish/Entity/Detail.swift new file mode 100644 index 000000000..ec1f2cda0 --- /dev/null +++ b/Sidedish/Sidedish/Entity/Detail.swift @@ -0,0 +1,12 @@ +// +// Detail.swift +// Sidedish +// +// Created by Issac on 2021/04/27. +// + +import Foundation + +class Detail: Codable { + var data: DetailItem +} diff --git a/Sidedish/Sidedish/Entity/DetailItem.swift b/Sidedish/Sidedish/Entity/DetailItem.swift new file mode 100644 index 000000000..8a6de61f7 --- /dev/null +++ b/Sidedish/Sidedish/Entity/DetailItem.swift @@ -0,0 +1,51 @@ +// +// DetailItem.swift +// Sidedish +// +// Created by Issac on 2021/04/27. +// + +import Foundation + +struct DetailItem: Codable { + var topImageURL: String + var topImageData: Data? + var thumbImagesURL: [String] + var thumbImagesData: [Data?]? + var productDescription: String + var point: String + var deliveryInfo: String + var deleveryFee: String + var prices: [String] + var detailSectionURL: [String] + var detailSectionData: [Data?]? + + enum CodingKeys: String, CodingKey { + case topImageURL = "top_image" + case topImageData + case thumbImagesURL = "thumb_images" + case thumbImagesData + case productDescription = "product_description" + case point + case deliveryInfo = "delivery_info" + case deleveryFee = "delivery_fee" + case prices + case detailSectionURL = "detail_section" + case detailSectionData + } + + init() { + self.topImageURL = "" + self.topImageData = nil + self.thumbImagesURL = [String]() + self.thumbImagesData = nil + self.productDescription = "" + self.point = "" + self.deliveryInfo = "" + self.deleveryFee = "" + self.prices = [String]() + self.detailSectionURL = [String]() + self.detailSectionData = nil + } + +} diff --git a/Sidedish/Sidedish/Repository/SidedishNetworkCenter.swift b/Sidedish/Sidedish/Repository/SidedishNetworkCenter.swift index 752519171..7576450f5 100644 --- a/Sidedish/Sidedish/Repository/SidedishNetworkCenter.swift +++ b/Sidedish/Sidedish/Repository/SidedishNetworkCenter.swift @@ -10,6 +10,7 @@ import Alamofire protocol Networkable { func fetchItems(url: String, completion: @escaping (Result<[SidedishItem], AFError>) -> ()) + func fetchDetail(url: String, completion: @escaping (Result) -> ()) func downloadImage(from url: URL, completion: @escaping ((Data) -> ()) ) } @@ -27,6 +28,19 @@ class SidedishNetworkCenter: Networkable { } } + func fetchDetail(url: String, completion: @escaping (Result) -> ()) { + AF.request(url).validate().responseDecodable(of: Detail.self) { (response) in + switch response.result { + case .success(let detail): + self.fetchDetailImgae(detail: detail) { (detail) in + completion(.success(detail.data)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + private func fetchImage(sidedishOfCategory: SidedishOfCategory, completion: @escaping (SidedishOfCategory) -> ()) { var originalSidedishs = sidedishOfCategory for (index, item) in sidedishOfCategory.body.enumerated() { @@ -38,6 +52,33 @@ class SidedishNetworkCenter: Networkable { } } + private func fetchDetailImgae(detail: Detail, completion: @escaping (Detail) -> ()) { + let originalDetail = detail + guard let url = URL(string: originalDetail.data.topImageURL) else { return } + self.downloadImage(from: url) { (data) in + originalDetail.data.topImageData = data + completion(originalDetail) + } + + originalDetail.data.thumbImagesData = Array(repeating: nil, count: originalDetail.data.thumbImagesURL.count) + for (index, thumbImageURL) in originalDetail.data.thumbImagesURL.enumerated() { + guard let url = URL(string: thumbImageURL) else { return } + self.downloadImage(from: url) { (data) in + originalDetail.data.thumbImagesData?[index] = data + completion(originalDetail) + } + } + + originalDetail.data.detailSectionData = Array(repeating: nil, count: originalDetail.data.detailSectionURL.count) + for (index, detailSectionURL) in originalDetail.data.detailSectionURL.enumerated() { + guard let url = URL(string: detailSectionURL) else { return } + self.downloadImage(from: url) { (data) in + originalDetail.data.detailSectionData?[index] = data + completion(originalDetail) + } + } + } + func downloadImage(from url: URL, completion: @escaping ((Data) -> ()) ) { URLSession.shared.dataTask(with: url) { (data, _, error) in if let error = error { diff --git a/Sidedish/Sidedish/UseCase/SidedishProcessing.swift b/Sidedish/Sidedish/UseCase/SidedishProcessing.swift index 63cbd15ec..23a3f8ded 100644 --- a/Sidedish/Sidedish/UseCase/SidedishProcessing.swift +++ b/Sidedish/Sidedish/UseCase/SidedishProcessing.swift @@ -10,6 +10,7 @@ import Alamofire protocol SidedishProcessable { func getItems(url: String, completion: @escaping (Result<[SidedishItem], AFError>) -> ()) + func getDetail(url: String, completion: @escaping (Result) -> ()) func getImage(url: URL, completion: @escaping ((Data) -> ())) } @@ -30,6 +31,17 @@ class SidedishProcessing: SidedishProcessable { } } + func getDetail(url: String, completion: @escaping (Result) -> ()) { + self.sideDishNetworkCenter.fetchDetail(url: url) { (result) in + switch result { + case .success(let detail): + completion(.success(detail)) + case .failure(let error): + completion(.failure(error)) + } + } + } + func getImage(url: URL, completion: @escaping ((Data) -> ())) { self.sideDishNetworkCenter.downloadImage(from: url) { (data) in completion(data) diff --git a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard index 500d9d8e2..e3b93f83f 100644 --- a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard +++ b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard @@ -191,75 +191,54 @@ - + - - + + - - + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - + + + + + - - + + - + - - - - + + + + + - + + - + diff --git a/Sidedish/Sidedish/ViewController.swift b/Sidedish/Sidedish/ViewController.swift index e433c295c..9a092df34 100644 --- a/Sidedish/Sidedish/ViewController.swift +++ b/Sidedish/Sidedish/ViewController.swift @@ -99,6 +99,21 @@ extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { print(indexPath.row, indexPath.section) } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if let cell = sender as? ItemCollectionViewCell, let indexPath = self.collectionView.indexPath(for: cell) { + guard let category = Category(rawValue: indexPath.section) else { return } + guard let items = self.itemViewModel.items[category.description] else { return } + let detailHash = items[indexPath.row].detailHash + + self.itemViewModel.fetchDetail(hash: detailHash) + let vc = segue.destination as? DetailViewController + vc?.itemViewModel = self.itemViewModel + } + if segue.destination is DetailViewController { + + } + } } extension ViewController: UICollectionViewDelegateFlowLayout { diff --git a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift index d4ec0de22..fee3868ab 100644 --- a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift +++ b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift @@ -9,14 +9,17 @@ import Foundation class ItemViewModel { var items: Dictionary + var currentDetail: DetailItem var imageReloadHandler: ((Int) -> ())? var errorHandler: ((String) -> ())? var reloadHandler: ((Category) -> ())? var sidedishProcessing: SidedishProcessable + var detailHandler: (() -> ())? init(sidedishProcessable: SidedishProcessable) { self.items = Dictionary() self.sidedishProcessing = sidedishProcessable + self.currentDetail = DetailItem() } func fetchItems(of category: Category) { @@ -37,6 +40,23 @@ class ItemViewModel { } } + func fetchDetail(hash: String) { + let url = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/detail/\(hash)" + self.sidedishProcessing.getDetail(url: url) { [weak self] (result) in + switch result { + case .success(let detailItem): + guard let strongSelf = self else { return } + strongSelf.currentDetail = detailItem + strongSelf.detailHandler?() + case .failure(let error): + #if DEBUG + NSLog(error.localizedDescription) + #endif + self?.errorHandler?(error.localizedDescription) + } + } + } + func setOriginalPrice(items: [SidedishItem]) -> [SidedishItem] { var processedItems = items processedItems.enumerated().forEach { (index, item) in From 8127f457199abefbe4665ecd45897ba63ac37311 Mon Sep 17 00:00:00 2001 From: okstring Date: Tue, 27 Apr 2021 15:07:25 +0900 Subject: [PATCH 05/20] =?UTF-8?q?Implement:=20thumbnail=20=E1=84=87?= =?UTF-8?q?=E1=85=AE=E1=84=87=E1=85=AE=E1=86=AB=20=E1=84=80=E1=85=AE?= =?UTF-8?q?=E1=84=92=E1=85=A7=E1=86=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sidedish/Sidedish.xcodeproj/project.pbxproj | 4 + Sidedish/Sidedish/DetailViewController.swift | 74 ++++++++++++------- .../Sidedish/View/Base.lproj/Main.storyboard | 65 +++++++++++----- Sidedish/Sidedish/ViewController.swift | 11 +-- .../Sidedish/ViewModel/DetailViewModel.swift | 38 ++++++++++ .../Sidedish/ViewModel/ItemViewModel.swift | 20 ----- 6 files changed, 142 insertions(+), 70 deletions(-) create mode 100644 Sidedish/Sidedish/ViewModel/DetailViewModel.swift diff --git a/Sidedish/Sidedish.xcodeproj/project.pbxproj b/Sidedish/Sidedish.xcodeproj/project.pbxproj index 7677e2e5f..6b2ce9dde 100644 --- a/Sidedish/Sidedish.xcodeproj/project.pbxproj +++ b/Sidedish/Sidedish.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 220B06922637D7D5009FAEFF /* DetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 220B06912637D7D5009FAEFF /* DetailViewModel.swift */; }; 222E3DB32636936600CB8330 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222E3DB22636936600CB8330 /* Category.swift */; }; 2240D5AC262D74890077EF4D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2240D5AB262D74890077EF4D /* DetailViewController.swift */; }; 2240D5B0262D7E500077EF4D /* ItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2240D5AF262D7E500077EF4D /* ItemViewModel.swift */; }; @@ -32,6 +33,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 220B06912637D7D5009FAEFF /* DetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewModel.swift; sourceTree = ""; }; 222E3DB22636936600CB8330 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; }; 2240D5AB262D74890077EF4D /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 2240D5AF262D7E500077EF4D /* ItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemViewModel.swift; sourceTree = ""; }; @@ -85,6 +87,7 @@ isa = PBXGroup; children = ( 2240D5AF262D7E500077EF4D /* ItemViewModel.swift */, + 220B06912637D7D5009FAEFF /* DetailViewModel.swift */, 22EBA5652633B332009611CB /* HeaderViewModel.swift */, ); path = ViewModel; @@ -305,6 +308,7 @@ 22418746262D4D8300AC14C7 /* ViewController.swift in Sources */, 22EBA5662633B332009611CB /* HeaderViewModel.swift in Sources */, D08A5398262D587700DD1CBE /* ItemCollectionViewCell.swift in Sources */, + 220B06922637D7D5009FAEFF /* DetailViewModel.swift in Sources */, 22418742262D4D8300AC14C7 /* AppDelegate.swift in Sources */, 22418771262D6A5A00AC14C7 /* SidedishItem.swift in Sources */, 22418761262D5C8400AC14C7 /* HeaderCollectionReusableView.swift in Sources */, diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index f8875a7aa..665e5d183 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -6,45 +6,69 @@ // import UIKit +import Toaster class DetailViewController: UIViewController { @IBOutlet weak var detailImages: UIStackView! - @IBOutlet weak var imageScrollView: UIScrollView! - @IBOutlet weak var contentView: UIView! - var itemViewModel: ItemViewModel! + @IBOutlet weak var thumbnailScrollView: UIScrollView! + @IBOutlet weak var thumbnailContentView: UIView! + @IBOutlet weak var thumbnailContentViewWidth: NSLayoutConstraint! + var detailViewModel: DetailViewModel! override func viewDidLoad() { super.viewDidLoad() + self.setThumbnailScrollView() + self.setDetailScrollView() - // 상세이미지 추가 - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true - detailImages.addArrangedSubview(imageView) - - itemViewModel.detailHandler = { - print(self.itemViewModel.currentDetail.detailSectionData) + detailViewModel.detailHandler = { + DispatchQueue.main.async { + self.setImage() + self.thumbnailContentViewWidth.constant = self.view.frame.width * CGFloat(self.detailViewModel.currentDetail.thumbImagesData?.count ?? 0) + } } - } - -private func setImage() { - let currentDetailItem = self.itemViewModel.currentDetail - self.imageScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) - self.imageScrollView.contentSize = CGSize(width: self.view.frame.width * CGFloat((currentDetailItem.thumbImagesData?.count ?? 0 + 1) ?? 0), height: self.view.frame.width) - self.imageScrollView.isPagingEnabled = true - - for index in 0..<(currentDetailItem.thumbImagesData?.count ?? 0) + 1{ + self.detailViewModel.errorHandler = { error in + Toast(text: error).show() + } } -} - -override func viewWillAppear(_ animated: Bool) { + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.isNavigationBarHidden = false } - func setImageScrollView() { - self.imageScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) + private func setThumbnailScrollView() { + self.thumbnailScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) + self.thumbnailScrollView.isPagingEnabled = true + } + + private func setImage() { + let currentDetailItem = self.detailViewModel.currentDetail + for index in 0..<(currentDetailItem.thumbImagesData?.count ?? 0) + 1{ + let imageView = UIImageView(frame: CGRect(x: thumbnailScrollView.frame.width * CGFloat(index), + y: 0, + width: self.thumbnailScrollView.frame.width, + height: self.thumbnailScrollView.frame.width)) + imageView.contentMode = .scaleAspectFit + if index == 0 { + guard let imageData = currentDetailItem.topImageData else { continue } + imageView.image = UIImage(data: imageData) + } else { + guard let imageData = currentDetailItem.thumbImagesData?[index - 1] else { continue } + imageView.image = UIImage(data: imageData) + } + + + self.thumbnailContentView.addSubview(imageView) + } + } + + private func setDetailScrollView() { + // 상세이미지 추가 + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true + detailImages.addArrangedSubview(imageView) + } } diff --git a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard index e3b93f83f..369c6895d 100644 --- a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard +++ b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard @@ -194,46 +194,75 @@ - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + - - + + - - - - + + + + - - + + + + diff --git a/Sidedish/Sidedish/ViewController.swift b/Sidedish/Sidedish/ViewController.swift index 9a092df34..a256b8500 100644 --- a/Sidedish/Sidedish/ViewController.swift +++ b/Sidedish/Sidedish/ViewController.swift @@ -22,7 +22,6 @@ class ViewController: UIViewController { super.viewDidLoad() let networking = SidedishNetworkCenter() let sidedishProcessing = SidedishProcessing(networkable: networking) - self.itemViewModel = ItemViewModel(sidedishProcessable: sidedishProcessing) self.headerViewModel = HeaderViewModel() self.bind() @@ -105,13 +104,11 @@ extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { guard let category = Category(rawValue: indexPath.section) else { return } guard let items = self.itemViewModel.items[category.description] else { return } let detailHash = items[indexPath.row].detailHash - - self.itemViewModel.fetchDetail(hash: detailHash) let vc = segue.destination as? DetailViewController - vc?.itemViewModel = self.itemViewModel - } - if segue.destination is DetailViewController { - + let networking = SidedishNetworkCenter() + let sidedishProcessing = SidedishProcessing(networkable: networking) + vc?.detailViewModel = DetailViewModel(sidedishProcessable: sidedishProcessing) + vc?.detailViewModel.fetchDetail(hash: detailHash) } } } diff --git a/Sidedish/Sidedish/ViewModel/DetailViewModel.swift b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift new file mode 100644 index 000000000..63f34dcc2 --- /dev/null +++ b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift @@ -0,0 +1,38 @@ +// +// DetailViewModel.swift +// Sidedish +// +// Created by Issac on 2021/04/27. +// + +import Foundation + +class DetailViewModel { + var sidedishProcessing: SidedishProcessable + var currentDetail: DetailItem + var detailHandler: (() -> ())? + var errorHandler: ((String) -> ())? + + init(sidedishProcessable: SidedishProcessable) { + self.sidedishProcessing = sidedishProcessable + self.currentDetail = DetailItem() + } + + func fetchDetail(hash: String) { + let url = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/detail/\(hash)" + self.sidedishProcessing.getDetail(url: url) { [weak self] (result) in + switch result { + case .success(let detailItem): + guard let strongSelf = self else { return } + strongSelf.currentDetail = detailItem + strongSelf.detailHandler?() + case .failure(let error): + #if DEBUG + NSLog(error.localizedDescription) + #endif + self?.errorHandler?(error.localizedDescription) + } + } + } + +} diff --git a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift index fee3868ab..d4ec0de22 100644 --- a/Sidedish/Sidedish/ViewModel/ItemViewModel.swift +++ b/Sidedish/Sidedish/ViewModel/ItemViewModel.swift @@ -9,17 +9,14 @@ import Foundation class ItemViewModel { var items: Dictionary - var currentDetail: DetailItem var imageReloadHandler: ((Int) -> ())? var errorHandler: ((String) -> ())? var reloadHandler: ((Category) -> ())? var sidedishProcessing: SidedishProcessable - var detailHandler: (() -> ())? init(sidedishProcessable: SidedishProcessable) { self.items = Dictionary() self.sidedishProcessing = sidedishProcessable - self.currentDetail = DetailItem() } func fetchItems(of category: Category) { @@ -40,23 +37,6 @@ class ItemViewModel { } } - func fetchDetail(hash: String) { - let url = "https://h3rb9c0ugl.execute-api.ap-northeast-2.amazonaws.com/develop/baminchan/detail/\(hash)" - self.sidedishProcessing.getDetail(url: url) { [weak self] (result) in - switch result { - case .success(let detailItem): - guard let strongSelf = self else { return } - strongSelf.currentDetail = detailItem - strongSelf.detailHandler?() - case .failure(let error): - #if DEBUG - NSLog(error.localizedDescription) - #endif - self?.errorHandler?(error.localizedDescription) - } - } - } - func setOriginalPrice(items: [SidedishItem]) -> [SidedishItem] { var processedItems = items processedItems.enumerated().forEach { (index, item) in From c03c40733489d4f680a5848506b343ef239edafb Mon Sep 17 00:00:00 2001 From: lena Date: Tue, 27 Apr 2021 17:04:34 +0900 Subject: [PATCH 06/20] Add detail Information custom view --- Sidedish/Sidedish.xcodeproj/project.pbxproj | 8 + Sidedish/Sidedish/DetailViewController.swift | 10 ++ .../Sidedish/View/Base.lproj/Main.storyboard | 32 ++-- Sidedish/Sidedish/View/CustomView.swift | 27 +++ Sidedish/Sidedish/View/CustomView.xib | 166 ++++++++++++++++++ .../Sidedish/ViewModel/DetailViewModel.swift | 1 + 6 files changed, 231 insertions(+), 13 deletions(-) create mode 100644 Sidedish/Sidedish/View/CustomView.swift create mode 100644 Sidedish/Sidedish/View/CustomView.xib diff --git a/Sidedish/Sidedish.xcodeproj/project.pbxproj b/Sidedish/Sidedish.xcodeproj/project.pbxproj index 6b2ce9dde..5eec15cb9 100644 --- a/Sidedish/Sidedish.xcodeproj/project.pbxproj +++ b/Sidedish/Sidedish.xcodeproj/project.pbxproj @@ -30,6 +30,8 @@ A46CDD6D47430A384FEB7271 /* Pods_Sidedish.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2266576CDB07714024C22C84 /* Pods_Sidedish.framework */; }; D06C739626310CD3002404A3 /* BadgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06C739526310CD3002404A3 /* BadgeLabel.swift */; }; D08A5398262D587700DD1CBE /* ItemCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */; }; + D0C1A7112637F95B005F6113 /* CustomView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D0C1A7102637F95B005F6113 /* CustomView.xib */; }; + D0C1A7142637F9A7005F6113 /* CustomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C1A7132637F9A7005F6113 /* CustomView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -59,6 +61,8 @@ 71EC35DD2BAA44FFBB2A183D /* Pods-Sidedish.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.debug.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.debug.xcconfig"; sourceTree = ""; }; D06C739526310CD3002404A3 /* BadgeLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeLabel.swift; sourceTree = ""; }; D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCollectionViewCell.swift; sourceTree = ""; }; + D0C1A7102637F95B005F6113 /* CustomView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomView.xib; sourceTree = ""; }; + D0C1A7132637F9A7005F6113 /* CustomView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomView.swift; sourceTree = ""; }; E7B0F586A26D135247BB28E9 /* Pods-Sidedish.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sidedish.release.xcconfig"; path = "Target Support Files/Pods-Sidedish/Pods-Sidedish.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -96,6 +100,8 @@ 2204E946262EC5A2008102BD /* View */ = { isa = PBXGroup; children = ( + D0C1A7102637F95B005F6113 /* CustomView.xib */, + D0C1A7132637F9A7005F6113 /* CustomView.swift */, 22418747262D4D8300AC14C7 /* Main.storyboard */, D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */, 22418760262D5C8400AC14C7 /* HeaderCollectionReusableView.swift */, @@ -249,6 +255,7 @@ 2241874E262D4D8600AC14C7 /* LaunchScreen.storyboard in Resources */, 2241874B262D4D8600AC14C7 /* Assets.xcassets in Resources */, 22418749262D4D8300AC14C7 /* Main.storyboard in Resources */, + D0C1A7112637F95B005F6113 /* CustomView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -304,6 +311,7 @@ D06C739626310CD3002404A3 /* BadgeLabel.swift in Sources */, 22D5024A2633049700325C5F /* String+NSAttributedString.swift in Sources */, 228295C32637813C00BBDACD /* Detail.swift in Sources */, + D0C1A7142637F9A7005F6113 /* CustomView.swift in Sources */, 2291A1A926326FD6007A1B72 /* Badge.swift in Sources */, 22418746262D4D8300AC14C7 /* ViewController.swift in Sources */, 22EBA5662633B332009611CB /* HeaderViewModel.swift in Sources */, diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index 665e5d183..1a92f680d 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -13,6 +13,8 @@ class DetailViewController: UIViewController { @IBOutlet weak var thumbnailScrollView: UIScrollView! @IBOutlet weak var thumbnailContentView: UIView! @IBOutlet weak var thumbnailContentViewWidth: NSLayoutConstraint! + @IBOutlet weak var informationStackView: UIStackView! + var detailViewModel: DetailViewModel! override func viewDidLoad() { @@ -24,6 +26,7 @@ class DetailViewController: UIViewController { DispatchQueue.main.async { self.setImage() self.thumbnailContentViewWidth.constant = self.view.frame.width * CGFloat(self.detailViewModel.currentDetail.thumbImagesData?.count ?? 0) + self.setInformationView() } } @@ -32,6 +35,13 @@ class DetailViewController: UIViewController { } } + private func setInformationView() { + if let view = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)?.first as? CustomView { + view.configure(item: detailViewModel.currentDetail) + informationStackView.addArrangedSubview(view) + } + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.isNavigationBarHidden = false diff --git a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard index 369c6895d..8a75a465e 100644 --- a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard +++ b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard @@ -198,13 +198,13 @@ - + - - + + - - + + @@ -217,17 +217,22 @@ - - - + + + + + + + + - - - - + + + + @@ -239,7 +244,7 @@ - + @@ -260,6 +265,7 @@ + diff --git a/Sidedish/Sidedish/View/CustomView.swift b/Sidedish/Sidedish/View/CustomView.swift new file mode 100644 index 000000000..a4c0e1446 --- /dev/null +++ b/Sidedish/Sidedish/View/CustomView.swift @@ -0,0 +1,27 @@ +// +// CustomView.swift +// Sidedish +// +// Created by Ador on 2021/04/27. +// + +import UIKit + +class CustomView: UIView { + + @IBOutlet weak var title: UILabel! + @IBOutlet weak var productDescription: UILabel! + @IBOutlet weak var point: UILabel! + @IBOutlet weak var deliveryInfo: UILabel! + @IBOutlet weak var deliveryFee: UILabel! + @IBOutlet weak var prices: UILabel! + + func configure(productName: String = "", item: DetailItem) { + title.text = productName + productDescription.text = item.productDescription + point.text = item.point + deliveryInfo.text = item.deliveryInfo + deliveryFee.text = item.deleveryFee + prices.text = item.prices.first + } +} diff --git a/Sidedish/Sidedish/View/CustomView.xib b/Sidedish/Sidedish/View/CustomView.xib new file mode 100644 index 000000000..5c4598f3c --- /dev/null +++ b/Sidedish/Sidedish/View/CustomView.xib @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sidedish/Sidedish/ViewModel/DetailViewModel.swift b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift index 63f34dcc2..77b6d45cf 100644 --- a/Sidedish/Sidedish/ViewModel/DetailViewModel.swift +++ b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift @@ -26,6 +26,7 @@ class DetailViewModel { guard let strongSelf = self else { return } strongSelf.currentDetail = detailItem strongSelf.detailHandler?() + print(detailItem) case .failure(let error): #if DEBUG NSLog(error.localizedDescription) From e9b193d6ae2bb8285bf89454f1df80c4ac6d6e29 Mon Sep 17 00:00:00 2001 From: okstring Date: Tue, 27 Apr 2021 17:05:15 +0900 Subject: [PATCH 07/20] Enable Scroll --- Sidedish/Sidedish/DetailViewController.swift | 36 +++++++++++++------ .../Sidedish/View/Base.lproj/Main.storyboard | 32 ++++++++--------- .../Sidedish/ViewModel/DetailViewModel.swift | 6 ++-- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index 1a92f680d..d7fde78ac 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -20,16 +20,18 @@ class DetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.setThumbnailScrollView() - self.setDetailScrollView() - detailViewModel.detailHandler = { + detailViewModel.imageFetchHandler = { DispatchQueue.main.async { self.setImage() - self.thumbnailContentViewWidth.constant = self.view.frame.width * CGFloat(self.detailViewModel.currentDetail.thumbImagesData?.count ?? 0) - self.setInformationView() + self.setDetailScrollView() } } + detailViewModel.detailImageFetchHandler = { + + } + self.detailViewModel.errorHandler = { error in Toast(text: error).show() } @@ -54,6 +56,9 @@ class DetailViewController: UIViewController { private func setImage() { let currentDetailItem = self.detailViewModel.currentDetail + self.thumbnailContentView.subviews.forEach { (view) in + view.removeFromSuperview() + } for index in 0..<(currentDetailItem.thumbImagesData?.count ?? 0) + 1{ let imageView = UIImageView(frame: CGRect(x: thumbnailScrollView.frame.width * CGFloat(index), y: 0, @@ -68,17 +73,28 @@ class DetailViewController: UIViewController { imageView.image = UIImage(data: imageData) } - + self.thumbnailContentViewWidth.constant = self.view.frame.width * CGFloat(self.detailViewModel.currentDetail.thumbImagesData?.count ?? 0) self.thumbnailContentView.addSubview(imageView) } } private func setDetailScrollView() { - // 상세이미지 추가 - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true - detailImages.addArrangedSubview(imageView) + guard let thumbImagesData = self.detailViewModel.currentDetail.thumbImagesData else { return } + guard let detailSectionData = self.detailViewModel.currentDetail.detailSectionData else { return } + guard detailSectionData.filter({ $0 == nil }).isEmpty, + thumbImagesData.filter({ $0 == nil }).isEmpty else { return } + + + for index in 0.. - + - - + + @@ -212,27 +212,23 @@ - + - - - - - - - - + + + - - - - + + + + + @@ -242,9 +238,9 @@ - + - + diff --git a/Sidedish/Sidedish/ViewModel/DetailViewModel.swift b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift index 77b6d45cf..62a7a71cf 100644 --- a/Sidedish/Sidedish/ViewModel/DetailViewModel.swift +++ b/Sidedish/Sidedish/ViewModel/DetailViewModel.swift @@ -10,7 +10,8 @@ import Foundation class DetailViewModel { var sidedishProcessing: SidedishProcessable var currentDetail: DetailItem - var detailHandler: (() -> ())? + var imageFetchHandler: (() -> ())? + var detailImageFetchHandler: (() -> ())? var errorHandler: ((String) -> ())? init(sidedishProcessable: SidedishProcessable) { @@ -25,8 +26,7 @@ class DetailViewModel { case .success(let detailItem): guard let strongSelf = self else { return } strongSelf.currentDetail = detailItem - strongSelf.detailHandler?() - print(detailItem) + strongSelf.imageFetchHandler?() case .failure(let error): #if DEBUG NSLog(error.localizedDescription) From 12abd5e16816fb63a186e3264b511e8b280b06ed Mon Sep 17 00:00:00 2001 From: okstring Date: Wed, 28 Apr 2021 12:30:45 +0900 Subject: [PATCH 08/20] =?UTF-8?q?Fix:=20xib=20=E1=84=8B=E1=85=B1=E1=84=8E?= =?UTF-8?q?=E1=85=B5=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sidedish/Sidedish/DetailViewController.swift | 34 +++++++++---------- .../Sidedish/View/Base.lproj/Main.storyboard | 28 +++++++-------- Sidedish/Sidedish/View/CustomView.xib | 11 ++---- Sidedish/Sidedish/ViewController.swift | 4 ++- 4 files changed, 35 insertions(+), 42 deletions(-) diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index d7fde78ac..113b330b4 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -9,7 +9,6 @@ import UIKit import Toaster class DetailViewController: UIViewController { - @IBOutlet weak var detailImages: UIStackView! @IBOutlet weak var thumbnailScrollView: UIScrollView! @IBOutlet weak var thumbnailContentView: UIView! @IBOutlet weak var thumbnailContentViewWidth: NSLayoutConstraint! @@ -23,7 +22,9 @@ class DetailViewController: UIViewController { detailViewModel.imageFetchHandler = { DispatchQueue.main.async { - self.setImage() + self.clearImage() + self.setThumdnailImage() + self.setInformationView() self.setDetailScrollView() } } @@ -37,10 +38,21 @@ class DetailViewController: UIViewController { } } + private func clearImage() { + for subview in self.informationStackView.subviews { + subview.removeFromSuperview() + } + self.thumbnailContentView.subviews.forEach { (view) in + view.removeFromSuperview() + } + } + private func setInformationView() { if let view = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)?.first as? CustomView { view.configure(item: detailViewModel.currentDetail) - informationStackView.addArrangedSubview(view) + view.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true + view.heightAnchor.constraint(equalToConstant: view.frame.height).isActive = true + self.informationStackView.insertArrangedSubview(view, at: 0) } } @@ -54,11 +66,8 @@ class DetailViewController: UIViewController { self.thumbnailScrollView.isPagingEnabled = true } - private func setImage() { + private func setThumdnailImage() { let currentDetailItem = self.detailViewModel.currentDetail - self.thumbnailContentView.subviews.forEach { (view) in - view.removeFromSuperview() - } for index in 0..<(currentDetailItem.thumbImagesData?.count ?? 0) + 1{ let imageView = UIImageView(frame: CGRect(x: thumbnailScrollView.frame.width * CGFloat(index), y: 0, @@ -79,22 +88,13 @@ class DetailViewController: UIViewController { } private func setDetailScrollView() { - guard let thumbImagesData = self.detailViewModel.currentDetail.thumbImagesData else { return } guard let detailSectionData = self.detailViewModel.currentDetail.detailSectionData else { return } - guard detailSectionData.filter({ $0 == nil }).isEmpty, - thumbImagesData.filter({ $0 == nil }).isEmpty else { return } - - for index in 0.. - @@ -260,8 +259,7 @@ - - + diff --git a/Sidedish/Sidedish/View/CustomView.xib b/Sidedish/Sidedish/View/CustomView.xib index 5c4598f3c..b94b8aead 100644 --- a/Sidedish/Sidedish/View/CustomView.xib +++ b/Sidedish/Sidedish/View/CustomView.xib @@ -4,15 +4,13 @@ - - + - @@ -137,7 +135,7 @@ - + @@ -158,9 +156,4 @@ - - - - - diff --git a/Sidedish/Sidedish/ViewController.swift b/Sidedish/Sidedish/ViewController.swift index a256b8500..c2e573ef1 100644 --- a/Sidedish/Sidedish/ViewController.swift +++ b/Sidedish/Sidedish/ViewController.swift @@ -54,6 +54,7 @@ class ViewController: UIViewController { self.collectionView.reloadItems(at: [IndexPath(index: index)]) } } + } extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { @@ -70,7 +71,8 @@ extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { } guard let category = Category.init(rawValue: indexPath.section) else { return cell } - guard let item = self.itemViewModel.items[category.description]?[indexPath.row] else { return cell } + guard let items = self.itemViewModel.items[category.description] else { return cell } + let item = items[indexPath.row] let badge = handleBadge(badge: item.badge) cell.configure(model: item, nPrice: item.nPrice, badge: badge) guard let data = item.imageData else { return cell } From d22d525cbc4574e5b82c1661cf5f73f261cd019d Mon Sep 17 00:00:00 2001 From: okstring Date: Wed, 28 Apr 2021 16:23:19 +0900 Subject: [PATCH 09/20] =?UTF-8?q?implement:=20detail=20View=20layout=20?= =?UTF-8?q?=E1=84=80=E1=85=AE=E1=84=92=E1=85=A7=E1=86=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sidedish/Sidedish.xcodeproj/project.pbxproj | 10 ++++++- Sidedish/Sidedish/DetailViewController.swift | 27 ++++++++++++------- .../Sidedish/View/Base.lproj/Main.storyboard | 17 ++++++------ Sidedish/Sidedish/View/CustomView.xib | 24 ++++++++++------- .../String+NSAttributedString.swift | 0 Sidedish/Sidedish/ViewController.swift | 24 ++++++++--------- .../Sidedish/ViewModel/DetailViewModel.swift | 4 +-- 7 files changed, 63 insertions(+), 43 deletions(-) rename Sidedish/Sidedish/{ => View/extension}/String+NSAttributedString.swift (100%) diff --git a/Sidedish/Sidedish.xcodeproj/project.pbxproj b/Sidedish/Sidedish.xcodeproj/project.pbxproj index 5eec15cb9..32823166f 100644 --- a/Sidedish/Sidedish.xcodeproj/project.pbxproj +++ b/Sidedish/Sidedish.xcodeproj/project.pbxproj @@ -106,6 +106,7 @@ D08A5397262D587700DD1CBE /* ItemCollectionViewCell.swift */, 22418760262D5C8400AC14C7 /* HeaderCollectionReusableView.swift */, D06C739526310CD3002404A3 /* BadgeLabel.swift */, + 22E32CC226392CF200EE3AF8 /* extension */, ); path = View; sourceTree = ""; @@ -141,7 +142,6 @@ 2245D890262D92D700E0B637 /* Repository */, 22418776262D6C1700AC14C7 /* Entity */, 2241874C262D4D8600AC14C7 /* LaunchScreen.storyboard */, - 22D502492633049700325C5F /* String+NSAttributedString.swift */, 2241874F262D4D8600AC14C7 /* Info.plist */, 2241874A262D4D8600AC14C7 /* Assets.xcassets */, ); @@ -185,6 +185,14 @@ path = Enum; sourceTree = ""; }; + 22E32CC226392CF200EE3AF8 /* extension */ = { + isa = PBXGroup; + children = ( + 22D502492633049700325C5F /* String+NSAttributedString.swift */, + ); + path = extension; + sourceTree = ""; + }; E82A359D5367162E8BD6F247 /* Frameworks */ = { isa = PBXGroup; children = ( diff --git a/Sidedish/Sidedish/DetailViewController.swift b/Sidedish/Sidedish/DetailViewController.swift index 113b330b4..b456289ef 100644 --- a/Sidedish/Sidedish/DetailViewController.swift +++ b/Sidedish/Sidedish/DetailViewController.swift @@ -22,6 +22,7 @@ class DetailViewController: UIViewController { detailViewModel.imageFetchHandler = { DispatchQueue.main.async { + self.setTitle() self.clearImage() self.setThumdnailImage() self.setInformationView() @@ -29,15 +30,20 @@ class DetailViewController: UIViewController { } } - detailViewModel.detailImageFetchHandler = { - - } - self.detailViewModel.errorHandler = { error in Toast(text: error).show() } } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.isNavigationBarHidden = false + } + + private func setTitle() { + self.title = self.detailViewModel.currentDetail.productDescription + } + private func clearImage() { for subview in self.informationStackView.subviews { subview.removeFromSuperview() @@ -56,14 +62,8 @@ class DetailViewController: UIViewController { } } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - self.navigationController?.isNavigationBarHidden = false - } - private func setThumbnailScrollView() { self.thumbnailScrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.width) - self.thumbnailScrollView.isPagingEnabled = true } private func setThumdnailImage() { @@ -94,7 +94,14 @@ class DetailViewController: UIViewController { guard let data = detailSectionData[index] else { continue } imageView.image = UIImage(data: data) imageView.contentMode = .scaleAspectFit + let ratio = calculateImageRatioOfImageView(imageView.image) + imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: ratio).isActive = true informationStackView.addArrangedSubview(imageView) } } + + private func calculateImageRatioOfImageView(_ image: UIImage?) -> CGFloat { + guard let image = image else { return 0 } + return image.size.height / image.size.width + } } diff --git a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard index 6e3bcbe58..bcba50cfb 100644 --- a/Sidedish/Sidedish/View/Base.lproj/Main.storyboard +++ b/Sidedish/Sidedish/View/Base.lproj/Main.storyboard @@ -49,13 +49,13 @@ -