├── README.md ├── ZaraApp.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcuserdata │ └── temi.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── ZaraApp ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json ├── background.colorset │ └── Contents.json └── text.colorset │ └── Contents.json ├── ContentView.swift ├── Data └── Store.swift ├── Extensions └── Color+.swift ├── Models ├── Category.swift ├── Home.swift ├── Page.swift ├── Product.swift └── Tab.swift ├── Preview Content └── Preview Assets.xcassets │ └── Contents.json ├── Screens ├── HomeScreen.swift ├── LoginScreen.swift ├── ProductDetailScreen.swift └── ProductListScreen.swift ├── UIKit ├── CollectionCell.swift └── CollectionView.swift ├── Utils └── Sizes.swift ├── Views ├── Buttons │ ├── ArrowButton.swift │ ├── BorderedButton.swift │ ├── CloseButton.swift │ ├── FilledButton.swift │ ├── LargeNakedButton.swift │ ├── NakedButton.swift │ └── iconButton.swift ├── ClearNavBar.swift ├── CustomSheet.swift ├── ImagePageView.swift ├── NavBar.swift ├── PageController.swift ├── PageView.swift ├── ProductDetailContent.swift ├── ProductImageView.swift ├── ProductItemView.swift ├── TabBarView.swift ├── TabIndicator.swift ├── TabIndicatorItem.swift ├── VerticalPageIndicator.swift └── View+.swift └── ZaraAppApp.swift /README.md: -------------------------------------------------------------------------------- 1 | # ZaraApp 2 | 3 | E-commerce App with SwiftUI, UIKit & TCA Architecture. 4 | 5 | iOS ( Light Mode ) 6 | 7 | ![ZaraAppWhite1](https://user-images.githubusercontent.com/91268094/210820886-19e708d7-6c52-41a9-9ed0-91b35f4798e5.png) 8 | 9 | iOS ( Dark Mode ) 10 | 11 | ![ZaraAppblack1](https://user-images.githubusercontent.com/91268094/210820891-6a3a29dd-10f1-4a9f-9ef1-2d3fd101ea09.png) 12 | -------------------------------------------------------------------------------- /ZaraApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A72A91782962FEDD00972AB9 /* Page.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A91772962FEDD00972AB9 /* Page.swift */; }; 11 | A72A917A2962FFF400972AB9 /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A91792962FFF400972AB9 /* Home.swift */; }; 12 | A72A917C296301A600972AB9 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A917B296301A600972AB9 /* Store.swift */; }; 13 | A72A917E296333FF00972AB9 /* CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A917D296333FF00972AB9 /* CollectionView.swift */; }; 14 | A72A9180296393B700972AB9 /* CollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A917F296393B700972AB9 /* CollectionCell.swift */; }; 15 | A72A918229639AD900972AB9 /* PageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A918129639AD900972AB9 /* PageView.swift */; }; 16 | A72A918429639ED300972AB9 /* Sizes.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A918329639ED300972AB9 /* Sizes.swift */; }; 17 | A72A91862963A12B00972AB9 /* VerticalPageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72A91852963A12B00972AB9 /* VerticalPageIndicator.swift */; }; 18 | A77380E429610608008965BB /* ZaraAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A77380E329610608008965BB /* ZaraAppApp.swift */; }; 19 | A77380E629610608008965BB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A77380E529610608008965BB /* ContentView.swift */; }; 20 | A77380E82961060A008965BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A77380E72961060A008965BB /* Assets.xcassets */; }; 21 | A77380EB2961060A008965BB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A77380EA2961060A008965BB /* Preview Assets.xcassets */; }; 22 | A79F1DE52966AE800000A0E6 /* ImagePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DE42966AE800000A0E6 /* ImagePageView.swift */; }; 23 | A79F1DE72966DC260000A0E6 /* ProductImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DE62966DC260000A0E6 /* ProductImageView.swift */; }; 24 | A79F1DE92966ECBC0000A0E6 /* ProductDetailContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DE82966ECBC0000A0E6 /* ProductDetailContent.swift */; }; 25 | A79F1DEB2966EF5B0000A0E6 /* ArrowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DEA2966EF5B0000A0E6 /* ArrowButton.swift */; }; 26 | A79F1DED2966F3EF0000A0E6 /* ClearNavBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DEC2966F3EF0000A0E6 /* ClearNavBar.swift */; }; 27 | A79F1DEF29670EF10000A0E6 /* ProductDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79F1DEE29670EF10000A0E6 /* ProductDetailScreen.swift */; }; 28 | A7AC3CC42966336E009A29B3 /* CustomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AC3CC32966336E009A29B3 /* CustomSheet.swift */; }; 29 | A7C7BC0A29618243004D3446 /* Color+.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC0929618243004D3446 /* Color+.swift */; }; 30 | A7C7BC0C2961ED12004D3446 /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC0B2961ED12004D3446 /* View+.swift */; }; 31 | A7C7BC0F2961FCBB004D3446 /* CloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC0E2961FCBB004D3446 /* CloseButton.swift */; }; 32 | A7C7BC1129620033004D3446 /* BorderedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC1029620033004D3446 /* BorderedButton.swift */; }; 33 | A7C7BC13296235A5004D3446 /* iconButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC12296235A5004D3446 /* iconButton.swift */; }; 34 | A7C7BC1529623680004D3446 /* FilledButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC1429623680004D3446 /* FilledButton.swift */; }; 35 | A7C7BC1729623B14004D3446 /* NakedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC1629623B14004D3446 /* NakedButton.swift */; }; 36 | A7C7BC1929623E23004D3446 /* LargeNakedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC1829623E23004D3446 /* LargeNakedButton.swift */; }; 37 | A7C7BC1B29623F50004D3446 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C7BC1A29623F50004D3446 /* LoginScreen.swift */; }; 38 | A7ED8B10296410D70037738E /* PageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED8B0F296410D70037738E /* PageController.swift */; }; 39 | A7ED8B12296448520037738E /* TabIndicatorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED8B11296448520037738E /* TabIndicatorItem.swift */; }; 40 | A7ED8B1429644C850037738E /* TabIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED8B1329644C850037738E /* TabIndicator.swift */; }; 41 | A7ED8B162964556A0037738E /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED8B152964556A0037738E /* HomeScreen.swift */; }; 42 | A7EDC2D929649B9D000737EE /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7EDC2D829649B9D000737EE /* TabBarView.swift */; }; 43 | A7EDC2DC2964AC2E000737EE /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = A7EDC2DB2964AC2E000737EE /* Kingfisher */; }; 44 | A7EDC2DE2964ACE7000737EE /* ProductItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7EDC2DD2964ACE7000737EE /* ProductItemView.swift */; }; 45 | A7EDC2E02964BBF4000737EE /* NavBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7EDC2DF2964BBF4000737EE /* NavBar.swift */; }; 46 | A7EDC2E22964C3DB000737EE /* ProductListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7EDC2E12964C3DB000737EE /* ProductListScreen.swift */; }; 47 | A7F65BE92962D26F0042E570 /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F65BE82962D26F0042E570 /* Tab.swift */; }; 48 | A7F65BEB2962D3B60042E570 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F65BEA2962D3B60042E570 /* Category.swift */; }; 49 | A7F65BED2962E9F90042E570 /* Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F65BEC2962E9F90042E570 /* Product.swift */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | A72A91772962FEDD00972AB9 /* Page.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Page.swift; sourceTree = ""; }; 54 | A72A91792962FFF400972AB9 /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = ""; }; 55 | A72A917B296301A600972AB9 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; 56 | A72A917D296333FF00972AB9 /* CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionView.swift; sourceTree = ""; }; 57 | A72A917F296393B700972AB9 /* CollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionCell.swift; sourceTree = ""; }; 58 | A72A918129639AD900972AB9 /* PageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageView.swift; sourceTree = ""; }; 59 | A72A918329639ED300972AB9 /* Sizes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sizes.swift; sourceTree = ""; }; 60 | A72A91852963A12B00972AB9 /* VerticalPageIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalPageIndicator.swift; sourceTree = ""; }; 61 | A77380E029610608008965BB /* ZaraApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZaraApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | A77380E329610608008965BB /* ZaraAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZaraAppApp.swift; sourceTree = ""; }; 63 | A77380E529610608008965BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 64 | A77380E72961060A008965BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 65 | A77380EA2961060A008965BB /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 66 | A79F1DE42966AE800000A0E6 /* ImagePageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePageView.swift; sourceTree = ""; }; 67 | A79F1DE62966DC260000A0E6 /* ProductImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductImageView.swift; sourceTree = ""; }; 68 | A79F1DE82966ECBC0000A0E6 /* ProductDetailContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailContent.swift; sourceTree = ""; }; 69 | A79F1DEA2966EF5B0000A0E6 /* ArrowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowButton.swift; sourceTree = ""; }; 70 | A79F1DEC2966F3EF0000A0E6 /* ClearNavBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearNavBar.swift; sourceTree = ""; }; 71 | A79F1DEE29670EF10000A0E6 /* ProductDetailScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailScreen.swift; sourceTree = ""; }; 72 | A7AC3CC32966336E009A29B3 /* CustomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSheet.swift; sourceTree = ""; }; 73 | A7C7BC0929618243004D3446 /* Color+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+.swift"; sourceTree = ""; }; 74 | A7C7BC0B2961ED12004D3446 /* View+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = ""; }; 75 | A7C7BC0E2961FCBB004D3446 /* CloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseButton.swift; sourceTree = ""; }; 76 | A7C7BC1029620033004D3446 /* BorderedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BorderedButton.swift; sourceTree = ""; }; 77 | A7C7BC12296235A5004D3446 /* iconButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iconButton.swift; sourceTree = ""; }; 78 | A7C7BC1429623680004D3446 /* FilledButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilledButton.swift; sourceTree = ""; }; 79 | A7C7BC1629623B14004D3446 /* NakedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NakedButton.swift; sourceTree = ""; }; 80 | A7C7BC1829623E23004D3446 /* LargeNakedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeNakedButton.swift; sourceTree = ""; }; 81 | A7C7BC1A29623F50004D3446 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = ""; }; 82 | A7ED8B0F296410D70037738E /* PageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageController.swift; sourceTree = ""; }; 83 | A7ED8B11296448520037738E /* TabIndicatorItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIndicatorItem.swift; sourceTree = ""; }; 84 | A7ED8B1329644C850037738E /* TabIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIndicator.swift; sourceTree = ""; }; 85 | A7ED8B152964556A0037738E /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = ""; }; 86 | A7EDC2D829649B9D000737EE /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = ""; }; 87 | A7EDC2DD2964ACE7000737EE /* ProductItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductItemView.swift; sourceTree = ""; }; 88 | A7EDC2DF2964BBF4000737EE /* NavBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavBar.swift; sourceTree = ""; }; 89 | A7EDC2E12964C3DB000737EE /* ProductListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductListScreen.swift; sourceTree = ""; }; 90 | A7F65BE82962D26F0042E570 /* Tab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tab.swift; sourceTree = ""; }; 91 | A7F65BEA2962D3B60042E570 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; }; 92 | A7F65BEC2962E9F90042E570 /* Product.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Product.swift; sourceTree = ""; }; 93 | /* End PBXFileReference section */ 94 | 95 | /* Begin PBXFrameworksBuildPhase section */ 96 | A77380DD29610608008965BB /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | A7EDC2DC2964AC2E000737EE /* Kingfisher in Frameworks */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXFrameworksBuildPhase section */ 105 | 106 | /* Begin PBXGroup section */ 107 | A77380D729610608008965BB = { 108 | isa = PBXGroup; 109 | children = ( 110 | A77380E229610608008965BB /* ZaraApp */, 111 | A77380E129610608008965BB /* Products */, 112 | ); 113 | sourceTree = ""; 114 | }; 115 | A77380E129610608008965BB /* Products */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | A77380E029610608008965BB /* ZaraApp.app */, 119 | ); 120 | name = Products; 121 | sourceTree = ""; 122 | }; 123 | A77380E229610608008965BB /* ZaraApp */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | A7F65BE72962D2590042E570 /* Models */, 127 | A77380F62961084F008965BB /* UIKit */, 128 | A77380F529610847008965BB /* Screens */, 129 | A77380F429610841008965BB /* Data */, 130 | A77380F329610835008965BB /* Extensions */, 131 | A77380F22961082C008965BB /* Utils */, 132 | A77380F129610815008965BB /* Views */, 133 | A77380E329610608008965BB /* ZaraAppApp.swift */, 134 | A77380E529610608008965BB /* ContentView.swift */, 135 | A77380E72961060A008965BB /* Assets.xcassets */, 136 | A77380E92961060A008965BB /* Preview Content */, 137 | ); 138 | path = ZaraApp; 139 | sourceTree = ""; 140 | }; 141 | A77380E92961060A008965BB /* Preview Content */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | A77380EA2961060A008965BB /* Preview Assets.xcassets */, 145 | ); 146 | path = "Preview Content"; 147 | sourceTree = ""; 148 | }; 149 | A77380F129610815008965BB /* Views */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | A7C7BC0D2961FCA0004D3446 /* Buttons */, 153 | A7C7BC0B2961ED12004D3446 /* View+.swift */, 154 | A72A918129639AD900972AB9 /* PageView.swift */, 155 | A72A91852963A12B00972AB9 /* VerticalPageIndicator.swift */, 156 | A7ED8B0F296410D70037738E /* PageController.swift */, 157 | A7ED8B11296448520037738E /* TabIndicatorItem.swift */, 158 | A7ED8B1329644C850037738E /* TabIndicator.swift */, 159 | A7EDC2D829649B9D000737EE /* TabBarView.swift */, 160 | A7EDC2DD2964ACE7000737EE /* ProductItemView.swift */, 161 | A7EDC2DF2964BBF4000737EE /* NavBar.swift */, 162 | A7AC3CC32966336E009A29B3 /* CustomSheet.swift */, 163 | A79F1DE42966AE800000A0E6 /* ImagePageView.swift */, 164 | A79F1DE62966DC260000A0E6 /* ProductImageView.swift */, 165 | A79F1DE82966ECBC0000A0E6 /* ProductDetailContent.swift */, 166 | A79F1DEC2966F3EF0000A0E6 /* ClearNavBar.swift */, 167 | ); 168 | path = Views; 169 | sourceTree = ""; 170 | }; 171 | A77380F22961082C008965BB /* Utils */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | A72A918329639ED300972AB9 /* Sizes.swift */, 175 | ); 176 | path = Utils; 177 | sourceTree = ""; 178 | }; 179 | A77380F329610835008965BB /* Extensions */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | A7C7BC0929618243004D3446 /* Color+.swift */, 183 | ); 184 | path = Extensions; 185 | sourceTree = ""; 186 | }; 187 | A77380F429610841008965BB /* Data */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | A72A917B296301A600972AB9 /* Store.swift */, 191 | ); 192 | path = Data; 193 | sourceTree = ""; 194 | }; 195 | A77380F529610847008965BB /* Screens */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | A7C7BC1A29623F50004D3446 /* LoginScreen.swift */, 199 | A7ED8B152964556A0037738E /* HomeScreen.swift */, 200 | A7EDC2E12964C3DB000737EE /* ProductListScreen.swift */, 201 | A79F1DEE29670EF10000A0E6 /* ProductDetailScreen.swift */, 202 | ); 203 | path = Screens; 204 | sourceTree = ""; 205 | }; 206 | A77380F62961084F008965BB /* UIKit */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | A72A917D296333FF00972AB9 /* CollectionView.swift */, 210 | A72A917F296393B700972AB9 /* CollectionCell.swift */, 211 | ); 212 | path = UIKit; 213 | sourceTree = ""; 214 | }; 215 | A7C7BC0D2961FCA0004D3446 /* Buttons */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | A7C7BC0E2961FCBB004D3446 /* CloseButton.swift */, 219 | A7C7BC1029620033004D3446 /* BorderedButton.swift */, 220 | A7C7BC12296235A5004D3446 /* iconButton.swift */, 221 | A7C7BC1429623680004D3446 /* FilledButton.swift */, 222 | A7C7BC1629623B14004D3446 /* NakedButton.swift */, 223 | A7C7BC1829623E23004D3446 /* LargeNakedButton.swift */, 224 | A79F1DEA2966EF5B0000A0E6 /* ArrowButton.swift */, 225 | ); 226 | path = Buttons; 227 | sourceTree = ""; 228 | }; 229 | A7F65BE72962D2590042E570 /* Models */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | A7F65BE82962D26F0042E570 /* Tab.swift */, 233 | A7F65BEA2962D3B60042E570 /* Category.swift */, 234 | A7F65BEC2962E9F90042E570 /* Product.swift */, 235 | A72A91772962FEDD00972AB9 /* Page.swift */, 236 | A72A91792962FFF400972AB9 /* Home.swift */, 237 | ); 238 | path = Models; 239 | sourceTree = ""; 240 | }; 241 | /* End PBXGroup section */ 242 | 243 | /* Begin PBXNativeTarget section */ 244 | A77380DF29610608008965BB /* ZaraApp */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = A77380EE2961060A008965BB /* Build configuration list for PBXNativeTarget "ZaraApp" */; 247 | buildPhases = ( 248 | A77380DC29610608008965BB /* Sources */, 249 | A77380DD29610608008965BB /* Frameworks */, 250 | A77380DE29610608008965BB /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | ); 256 | name = ZaraApp; 257 | packageProductDependencies = ( 258 | A7EDC2DB2964AC2E000737EE /* Kingfisher */, 259 | ); 260 | productName = ZaraApp; 261 | productReference = A77380E029610608008965BB /* ZaraApp.app */; 262 | productType = "com.apple.product-type.application"; 263 | }; 264 | /* End PBXNativeTarget section */ 265 | 266 | /* Begin PBXProject section */ 267 | A77380D829610608008965BB /* Project object */ = { 268 | isa = PBXProject; 269 | attributes = { 270 | BuildIndependentTargetsInParallel = 1; 271 | LastSwiftUpdateCheck = 1410; 272 | LastUpgradeCheck = 1410; 273 | TargetAttributes = { 274 | A77380DF29610608008965BB = { 275 | CreatedOnToolsVersion = 14.1; 276 | }; 277 | }; 278 | }; 279 | buildConfigurationList = A77380DB29610608008965BB /* Build configuration list for PBXProject "ZaraApp" */; 280 | compatibilityVersion = "Xcode 14.0"; 281 | developmentRegion = en; 282 | hasScannedForEncodings = 0; 283 | knownRegions = ( 284 | en, 285 | Base, 286 | ); 287 | mainGroup = A77380D729610608008965BB; 288 | packageReferences = ( 289 | A7EDC2DA2964AC2E000737EE /* XCRemoteSwiftPackageReference "Kingfisher" */, 290 | ); 291 | productRefGroup = A77380E129610608008965BB /* Products */; 292 | projectDirPath = ""; 293 | projectRoot = ""; 294 | targets = ( 295 | A77380DF29610608008965BB /* ZaraApp */, 296 | ); 297 | }; 298 | /* End PBXProject section */ 299 | 300 | /* Begin PBXResourcesBuildPhase section */ 301 | A77380DE29610608008965BB /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | A77380EB2961060A008965BB /* Preview Assets.xcassets in Resources */, 306 | A77380E82961060A008965BB /* Assets.xcassets in Resources */, 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | }; 310 | /* End PBXResourcesBuildPhase section */ 311 | 312 | /* Begin PBXSourcesBuildPhase section */ 313 | A77380DC29610608008965BB /* Sources */ = { 314 | isa = PBXSourcesBuildPhase; 315 | buildActionMask = 2147483647; 316 | files = ( 317 | A72A917E296333FF00972AB9 /* CollectionView.swift in Sources */, 318 | A7EDC2E22964C3DB000737EE /* ProductListScreen.swift in Sources */, 319 | A79F1DEF29670EF10000A0E6 /* ProductDetailScreen.swift in Sources */, 320 | A79F1DEB2966EF5B0000A0E6 /* ArrowButton.swift in Sources */, 321 | A7EDC2D929649B9D000737EE /* TabBarView.swift in Sources */, 322 | A7C7BC0F2961FCBB004D3446 /* CloseButton.swift in Sources */, 323 | A7C7BC1529623680004D3446 /* FilledButton.swift in Sources */, 324 | A7C7BC0C2961ED12004D3446 /* View+.swift in Sources */, 325 | A72A91862963A12B00972AB9 /* VerticalPageIndicator.swift in Sources */, 326 | A72A9180296393B700972AB9 /* CollectionCell.swift in Sources */, 327 | A7ED8B162964556A0037738E /* HomeScreen.swift in Sources */, 328 | A79F1DE52966AE800000A0E6 /* ImagePageView.swift in Sources */, 329 | A72A918229639AD900972AB9 /* PageView.swift in Sources */, 330 | A72A918429639ED300972AB9 /* Sizes.swift in Sources */, 331 | A7F65BE92962D26F0042E570 /* Tab.swift in Sources */, 332 | A7AC3CC42966336E009A29B3 /* CustomSheet.swift in Sources */, 333 | A7EDC2E02964BBF4000737EE /* NavBar.swift in Sources */, 334 | A7C7BC1129620033004D3446 /* BorderedButton.swift in Sources */, 335 | A77380E629610608008965BB /* ContentView.swift in Sources */, 336 | A7C7BC1929623E23004D3446 /* LargeNakedButton.swift in Sources */, 337 | A79F1DE92966ECBC0000A0E6 /* ProductDetailContent.swift in Sources */, 338 | A7ED8B12296448520037738E /* TabIndicatorItem.swift in Sources */, 339 | A79F1DED2966F3EF0000A0E6 /* ClearNavBar.swift in Sources */, 340 | A7C7BC1729623B14004D3446 /* NakedButton.swift in Sources */, 341 | A7C7BC0A29618243004D3446 /* Color+.swift in Sources */, 342 | A7ED8B10296410D70037738E /* PageController.swift in Sources */, 343 | A7F65BEB2962D3B60042E570 /* Category.swift in Sources */, 344 | A7EDC2DE2964ACE7000737EE /* ProductItemView.swift in Sources */, 345 | A72A917C296301A600972AB9 /* Store.swift in Sources */, 346 | A77380E429610608008965BB /* ZaraAppApp.swift in Sources */, 347 | A79F1DE72966DC260000A0E6 /* ProductImageView.swift in Sources */, 348 | A7ED8B1429644C850037738E /* TabIndicator.swift in Sources */, 349 | A7C7BC1B29623F50004D3446 /* LoginScreen.swift in Sources */, 350 | A7C7BC13296235A5004D3446 /* iconButton.swift in Sources */, 351 | A7F65BED2962E9F90042E570 /* Product.swift in Sources */, 352 | A72A917A2962FFF400972AB9 /* Home.swift in Sources */, 353 | A72A91782962FEDD00972AB9 /* Page.swift in Sources */, 354 | ); 355 | runOnlyForDeploymentPostprocessing = 0; 356 | }; 357 | /* End PBXSourcesBuildPhase section */ 358 | 359 | /* Begin XCBuildConfiguration section */ 360 | A77380EC2961060A008965BB /* Debug */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | ALWAYS_SEARCH_USER_PATHS = NO; 364 | CLANG_ANALYZER_NONNULL = YES; 365 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 367 | CLANG_ENABLE_MODULES = YES; 368 | CLANG_ENABLE_OBJC_ARC = YES; 369 | CLANG_ENABLE_OBJC_WEAK = YES; 370 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_COMMA = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INFINITE_RECURSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 383 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 384 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 385 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 386 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 387 | CLANG_WARN_STRICT_PROTOTYPES = YES; 388 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 389 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 390 | CLANG_WARN_UNREACHABLE_CODE = YES; 391 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 392 | COPY_PHASE_STRIP = NO; 393 | DEBUG_INFORMATION_FORMAT = dwarf; 394 | ENABLE_STRICT_OBJC_MSGSEND = YES; 395 | ENABLE_TESTABILITY = YES; 396 | GCC_C_LANGUAGE_STANDARD = gnu11; 397 | GCC_DYNAMIC_NO_PIC = NO; 398 | GCC_NO_COMMON_BLOCKS = YES; 399 | GCC_OPTIMIZATION_LEVEL = 0; 400 | GCC_PREPROCESSOR_DEFINITIONS = ( 401 | "DEBUG=1", 402 | "$(inherited)", 403 | ); 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 411 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 412 | MTL_FAST_MATH = YES; 413 | ONLY_ACTIVE_ARCH = YES; 414 | SDKROOT = iphoneos; 415 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 416 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 417 | }; 418 | name = Debug; 419 | }; 420 | A77380ED2961060A008965BB /* Release */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ALWAYS_SEARCH_USER_PATHS = NO; 424 | CLANG_ANALYZER_NONNULL = YES; 425 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 427 | CLANG_ENABLE_MODULES = YES; 428 | CLANG_ENABLE_OBJC_ARC = YES; 429 | CLANG_ENABLE_OBJC_WEAK = YES; 430 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 431 | CLANG_WARN_BOOL_CONVERSION = YES; 432 | CLANG_WARN_COMMA = YES; 433 | CLANG_WARN_CONSTANT_CONVERSION = YES; 434 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 435 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 436 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 437 | CLANG_WARN_EMPTY_BODY = YES; 438 | CLANG_WARN_ENUM_CONVERSION = YES; 439 | CLANG_WARN_INFINITE_RECURSION = YES; 440 | CLANG_WARN_INT_CONVERSION = YES; 441 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 442 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 443 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 444 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 445 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 446 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 447 | CLANG_WARN_STRICT_PROTOTYPES = YES; 448 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 449 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 450 | CLANG_WARN_UNREACHABLE_CODE = YES; 451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 452 | COPY_PHASE_STRIP = NO; 453 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 454 | ENABLE_NS_ASSERTIONS = NO; 455 | ENABLE_STRICT_OBJC_MSGSEND = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu11; 457 | GCC_NO_COMMON_BLOCKS = YES; 458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 459 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 460 | GCC_WARN_UNDECLARED_SELECTOR = YES; 461 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 462 | GCC_WARN_UNUSED_FUNCTION = YES; 463 | GCC_WARN_UNUSED_VARIABLE = YES; 464 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 465 | MTL_ENABLE_DEBUG_INFO = NO; 466 | MTL_FAST_MATH = YES; 467 | SDKROOT = iphoneos; 468 | SWIFT_COMPILATION_MODE = wholemodule; 469 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 470 | VALIDATE_PRODUCT = YES; 471 | }; 472 | name = Release; 473 | }; 474 | A77380EF2961060A008965BB /* Debug */ = { 475 | isa = XCBuildConfiguration; 476 | buildSettings = { 477 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 478 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 479 | CODE_SIGN_STYLE = Automatic; 480 | CURRENT_PROJECT_VERSION = 1; 481 | DEVELOPMENT_ASSET_PATHS = "\"ZaraApp/Preview Content\""; 482 | DEVELOPMENT_TEAM = 4Q6S759NWS; 483 | ENABLE_PREVIEWS = YES; 484 | GENERATE_INFOPLIST_FILE = YES; 485 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 486 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 487 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 488 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 489 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 490 | LD_RUNPATH_SEARCH_PATHS = ( 491 | "$(inherited)", 492 | "@executable_path/Frameworks", 493 | ); 494 | MARKETING_VERSION = 1.0; 495 | PRODUCT_BUNDLE_IDENTIFIER = Temi.ZaraApp; 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | SWIFT_EMIT_LOC_STRINGS = YES; 498 | SWIFT_VERSION = 5.0; 499 | TARGETED_DEVICE_FAMILY = "1,2"; 500 | }; 501 | name = Debug; 502 | }; 503 | A77380F02961060A008965BB /* Release */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 507 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 508 | CODE_SIGN_STYLE = Automatic; 509 | CURRENT_PROJECT_VERSION = 1; 510 | DEVELOPMENT_ASSET_PATHS = "\"ZaraApp/Preview Content\""; 511 | DEVELOPMENT_TEAM = 4Q6S759NWS; 512 | ENABLE_PREVIEWS = YES; 513 | GENERATE_INFOPLIST_FILE = YES; 514 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 515 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 516 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 517 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 518 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 519 | LD_RUNPATH_SEARCH_PATHS = ( 520 | "$(inherited)", 521 | "@executable_path/Frameworks", 522 | ); 523 | MARKETING_VERSION = 1.0; 524 | PRODUCT_BUNDLE_IDENTIFIER = Temi.ZaraApp; 525 | PRODUCT_NAME = "$(TARGET_NAME)"; 526 | SWIFT_EMIT_LOC_STRINGS = YES; 527 | SWIFT_VERSION = 5.0; 528 | TARGETED_DEVICE_FAMILY = "1,2"; 529 | }; 530 | name = Release; 531 | }; 532 | /* End XCBuildConfiguration section */ 533 | 534 | /* Begin XCConfigurationList section */ 535 | A77380DB29610608008965BB /* Build configuration list for PBXProject "ZaraApp" */ = { 536 | isa = XCConfigurationList; 537 | buildConfigurations = ( 538 | A77380EC2961060A008965BB /* Debug */, 539 | A77380ED2961060A008965BB /* Release */, 540 | ); 541 | defaultConfigurationIsVisible = 0; 542 | defaultConfigurationName = Release; 543 | }; 544 | A77380EE2961060A008965BB /* Build configuration list for PBXNativeTarget "ZaraApp" */ = { 545 | isa = XCConfigurationList; 546 | buildConfigurations = ( 547 | A77380EF2961060A008965BB /* Debug */, 548 | A77380F02961060A008965BB /* Release */, 549 | ); 550 | defaultConfigurationIsVisible = 0; 551 | defaultConfigurationName = Release; 552 | }; 553 | /* End XCConfigurationList section */ 554 | 555 | /* Begin XCRemoteSwiftPackageReference section */ 556 | A7EDC2DA2964AC2E000737EE /* XCRemoteSwiftPackageReference "Kingfisher" */ = { 557 | isa = XCRemoteSwiftPackageReference; 558 | repositoryURL = "https://github.com/onevcat/Kingfisher.git"; 559 | requirement = { 560 | kind = upToNextMajorVersion; 561 | minimumVersion = 7.0.0; 562 | }; 563 | }; 564 | /* End XCRemoteSwiftPackageReference section */ 565 | 566 | /* Begin XCSwiftPackageProductDependency section */ 567 | A7EDC2DB2964AC2E000737EE /* Kingfisher */ = { 568 | isa = XCSwiftPackageProductDependency; 569 | package = A7EDC2DA2964AC2E000737EE /* XCRemoteSwiftPackageReference "Kingfisher" */; 570 | productName = Kingfisher; 571 | }; 572 | /* End XCSwiftPackageProductDependency section */ 573 | }; 574 | rootObject = A77380D829610608008965BB /* Project object */; 575 | } 576 | -------------------------------------------------------------------------------- /ZaraApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZaraApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZaraApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "kingfisher", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/onevcat/Kingfisher.git", 7 | "state" : { 8 | "revision" : "44e891bdb61426a95e31492a67c7c0dfad1f87c5", 9 | "version" : "7.4.1" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /ZaraApp.xcodeproj/xcuserdata/temi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZaraApp.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ZaraApp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ZaraApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ZaraApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ZaraApp/Assets.xcassets/background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x00", 27 | "green" : "0x00", 28 | "red" : "0x00" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ZaraApp/Assets.xcassets/text.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x00", 9 | "green" : "0x00", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xFF", 27 | "green" : "0xFF", 28 | "red" : "0xFF" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ZaraApp/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | @EnvironmentObject private var store: Store 12 | @State private var presentScreen = false 13 | @State private var selectedTab: Tab? 14 | @State private var selectedCategory: Category? 15 | 16 | 17 | var body: some View { 18 | 19 | if store.state.isLogggedIn { 20 | 21 | CreateHomeScreen() 22 | 23 | } else { 24 | 25 | createLoginScreen() 26 | } 27 | } 28 | 29 | fileprivate func createLoginScreen() -> some View { 30 | 31 | return LoginScreen { 32 | 33 | 34 | }.transition(.move(edge: .bottom)) 35 | .animation(.easeOut) 36 | } 37 | 38 | fileprivate func CreateHomeScreen() -> some View { 39 | 40 | return ZStack(alignment: .bottom) { 41 | 42 | HomeScreen(category: $selectedCategory) 43 | TabBarView(tab: $selectedTab) 44 | }.fullScreenCover(isPresented: $presentScreen, content: { 45 | 46 | if selectedCategory != nil { 47 | 48 | ProductListScreen(category: $selectedCategory) 49 | } 50 | 51 | if let tab = selectedTab { 52 | 53 | createTabScreen(tab) 54 | 55 | } 56 | }).onChange(of: selectedCategory) { category in 57 | 58 | presentScreen.toggle() 59 | }.onChange(of: selectedTab) { newValue in 60 | 61 | presentScreen.toggle() 62 | } 63 | } 64 | 65 | @ViewBuilder 66 | private func createTabScreen(_ tab: Tab) -> some View { 67 | 68 | switch tab { 69 | 70 | case.bookmark: 71 | Text("Bookmark") 72 | 73 | case.cart: 74 | Text("shopping bar") 75 | 76 | case.search: 77 | Text("Search") 78 | 79 | case.profile: 80 | 81 | Text("profile") 82 | 83 | case.menu: 84 | Text("Menu") 85 | } 86 | } 87 | } 88 | 89 | struct ContentView_Previews: PreviewProvider { 90 | static var previews: some View { 91 | ContentView().environmentObject(Store()) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ZaraApp/Data/Store.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Store.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | class Store: ObservableObject { 12 | 13 | 14 | struct State { 15 | 16 | var products: [Product] 17 | var bookmarked: [Product] 18 | var shoppingCart: [Product] 19 | var isLogggedIn: Bool = true 20 | } 21 | 22 | enum Action { 23 | 24 | case addProducts(_ product: [Product]) 25 | case bookmark(_ product: Product) 26 | case removeFromBookmark(_ index: Int) 27 | case addToCart(_ product: Product) 28 | case login 29 | } 30 | 31 | @Published private(set) var state: State = .init(products: [], bookmarked: [], shoppingCart: []) 32 | 33 | func dispatch(_ action: Action) { 34 | 35 | reducer(state: &state, action: action) 36 | } 37 | 38 | 39 | func reducer(state: inout State, action: Action) { 40 | 41 | switch action { 42 | 43 | case .bookmark(let product): 44 | state.bookmarked.append(product) 45 | 46 | case.addToCart(let product): 47 | state.shoppingCart.append(product) 48 | 49 | case.removeFromBookmark(let index): 50 | state.bookmarked.remove(at: index) 51 | 52 | case.addProducts(let products): 53 | state.products = products 54 | 55 | case .login: 56 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { [weak self] in 57 | 58 | self?.state.isLogggedIn = true 59 | } 60 | 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ZaraApp/Extensions/Color+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color+.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | extension Color { 12 | 13 | static let background = Color("background") 14 | static let text = Color("text") 15 | } 16 | -------------------------------------------------------------------------------- /ZaraApp/Models/Category.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Category.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | enum Category: Int, CaseIterable { 11 | 12 | 13 | case men = 0 14 | case women = 1 15 | case kids = 2 16 | 17 | private var cases: [String] { 18 | 19 | ["Men", "Women", "Kids"] 20 | } 21 | 22 | func toString() -> String { 23 | 24 | cases[self.rawValue] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ZaraApp/Models/Home.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Home.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | struct Home: Identifiable, Hashable { 10 | 11 | var id: Category 12 | var pages: [Page] 13 | 14 | static func ==(lhs: Home, rhs: Home) -> Bool { 15 | 16 | lhs.id == rhs.id 17 | } 18 | 19 | static var data: [Home] { 20 | 21 | 22 | [ 23 | Home(id: Category.men, pages: [ 24 | Page( 25 | title: "NEW IN", 26 | description: "Explore this week's latest menswear pieces of the season curated for you. Autumn Winter Man Collection"), 27 | Page( 28 | title: "COLLECTION", 29 | description: "Discover this week's latest pieces from our latest collection. Autumn Winter Man Collection"), 30 | Page( 31 | title: "SHOES & BAGS", 32 | description: "Explore the new collection of Shoes and Bags. Autumn Winter Man Collection"), 33 | Page( 34 | title: "SALE", 35 | description: "ONLINE AND IN STORES"), 36 | Page( 37 | title: "CLOTHING CARE", 38 | description: "As part of our environment commitmnet, we have developed a guide to help reduce the impact of care process. #joinlife") 39 | ]), 40 | Home(id: Category.women, pages: [ 41 | Page( 42 | title: "NEW IN", 43 | description: "Explore this week's latest womenswear pieces of the season curated for you. Autumn Winter Woman Collection"), 44 | 45 | Page( 46 | title: "COLLECTION", 47 | description: "Discover this week's latest pieces from our latest collection. Autumn Winter Woman Collection"), 48 | 49 | Page( 50 | title: "SHOES & BAGS", 51 | description: "Explore the new collection of Shoes and Bags. Autumn Winter Woman Collection"), 52 | 53 | Page( 54 | title: "UP TO 50% OFF", 55 | description: "ONLINE AND IN STORES"), 56 | 57 | Page( 58 | title: "CLOTHING CARE", 59 | description: "As part of our environment commitmnet, we have developed a guide to help reduce the impact of care process. #joinlife") 60 | ]), 61 | Home(id: Category.kids, pages: [ 62 | Page( 63 | title: "NEW IN", 64 | description: "Explore this week's latest kidswear pieces of the season curated for you. Autumn Winter Kids Collection"), 65 | 66 | Page( 67 | title: "COLLECTION", 68 | description: "Discover this week's latest pieces from our latest collection. Autumn Winter Kids Collection"), 69 | 70 | Page( 71 | title: "SHOES & BAGS", 72 | description: "Explore the new collection of Shoes and Bags. Autumn Winter Kids Collection"), 73 | 74 | Page( 75 | title: "SALE", 76 | description: "ONLINE AND IN STORES"), 77 | 78 | Page( 79 | title: "CLOTHING CARE", 80 | description: "As part of our environment commitmnet, we have developed a guide to help reduce the impact of care process. #joinlife") 81 | ]) 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ZaraApp/Models/Page.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Page.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Page: Identifiable, Hashable { 11 | 12 | 13 | var id = UUID().uuidString 14 | var title: String 15 | var description: String 16 | 17 | 18 | static var `default`: Page { 19 | 20 | 21 | Page(title: "NEW IN", description: "Explore this week's latest menswear pieces of the season curated for you. Autumn Winter Man Collection") 22 | } 23 | 24 | static var data: [Page] { 25 | 26 | [ 27 | Page( 28 | title: "NEW IN", 29 | description: "Explore this week's latest menswear pieces of the season curated for you. Autumn Winter Man Collection"), 30 | Page( 31 | title: "COLLECTION", 32 | description: "Discover this week's latest pieces from our latest collection. Autumn Winter Man Collection"), 33 | Page( 34 | title: "SHOES & BAGS", 35 | description: "Explore the new collection of Shoes and Bags. Autumn Winter Man Collection"), 36 | Page( 37 | title: "SALE", 38 | description: "ONLINE AND IN STORES"), 39 | Page( 40 | title: "CLOTHING CARE", 41 | description: "As part of our environment commitmnet, we have developed a guide to help reduce the impact of care process. #joinlife") 42 | ] 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ZaraApp/Models/Product.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Product.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Product: Identifiable { 11 | 12 | var id = UUID().uuidString 13 | var mainImage: String 14 | var images: [String] 15 | var title: String 16 | var description: String 17 | var price: String 18 | var isFull: Bool 19 | var isNew: Bool 20 | 21 | static var men: [Product] { 22 | let data = [ 23 | "Denim": 24 | [ 25 | "https://images.unsplash.com/photo-1588544622467-6df9eef29c7a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 26 | "https://images.unsplash.com/photo-1541840031508-326b77c9a17e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 27 | "https://images.unsplash.com/flagged/photo-1573550398269-6600a22ffdae?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1211&q=20", 28 | "https://images.unsplash.com/photo-1566612088151-a477d6c17708?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 29 | "https://images.unsplash.com/photo-1580420885700-69f974d32374?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=80" 30 | ] 31 | , 32 | "Jackets": 33 | [ 34 | "https://images.unsplash.com/photo-1543076447-215ad9ba6923?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2167&q=20", 35 | "https://images.unsplash.com/photo-1524601885886-1bdd86a02f5a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 36 | "https://images.unsplash.com/photo-1518621888950-386251586966?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 37 | "https://images.unsplash.com/photo-1516756587022-7891ad56a8cd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 38 | "https://images.unsplash.com/photo-1530651844286-ea8a1029c53d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1300&q=20" 39 | ], 40 | "Shirts": 41 | [ 42 | "https://images.unsplash.com/flagged/photo-1564468781192-f023d514222d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2550&q=20", 43 | "https://images.unsplash.com/photo-1573766713733-18f875c7892d?ixlib=rb-1.2.1&auto=format&fit=crop&w=1235&q=20", 44 | "https://images.unsplash.com/photo-1453486030486-0a5ffcd82cd9?ixlib=rb-1.2.1&auto=format&fit=crop&w=1213&q=20", 45 | "https://images.unsplash.com/photo-1563630423918-b58f07336ac9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 46 | "https://images.unsplash.com/photo-1541612966290-b4e6d966de22?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20" 47 | ], 48 | "T-Shirts": 49 | [ 50 | "https://images.unsplash.com/photo-1562157873-818bc0726f68?ixlib=rb-1.2.1&auto=format&fit=crop&w=1164&q=20", 51 | "https://images.unsplash.com/photo-1524275539700-cf51138f679b?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 52 | "https://images.unsplash.com/photo-1504198458649-3128b932f49e?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 53 | "https://images.unsplash.com/photo-1581655353564-df123a1eb820?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 54 | "https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1600&q=20", 55 | "https://images.unsplash.com/photo-1489987707025-afc232f7ea0f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2550&q=20", 56 | "https://images.unsplash.com/photo-1416339698674-4f118dd3388b?ixlib=rb-1.2.1&auto=format&fit=crop&w=1276&q=20", 57 | "https://images.unsplash.com/photo-1583743814966-8936f5b7be1a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20" 58 | ], 59 | 60 | "Sneekers" : 61 | [ 62 | "https://images.unsplash.com/photo-1525966222134-fcfa99b8ae77?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1243&q=20", 63 | "https://images.unsplash.com/photo-1584735174914-6b1272458e3e?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 64 | "https://images.unsplash.com/photo-1560343090-f0409e92791a?ixlib=rb-1.2.1&auto=format&fit=crop&w=1300&q=20", 65 | "https://images.unsplash.com/photo-1560769629-975ec94e6a86?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1300&q=20", 66 | "https://images.unsplash.com/photo-1491553895911-0055eca6402d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1600&q=20", 67 | "https://images.unsplash.com/photo-1515955656352-a1fa3ffcd111?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2550&q=20", 68 | "https://images.unsplash.com/photo-1512374382149-233c42b6a83b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1275&q=20", 69 | "https://images.unsplash.com/photo-1584735174965-48c48d7edfde?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 70 | "https://images.unsplash.com/photo-1584735175077-df669dcd8b0a?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 71 | "https://images.unsplash.com/photo-1543508282-6319a3e2621f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1258&q=20" 72 | ], 73 | ] 74 | 75 | return generate(from: data) 76 | } 77 | 78 | 79 | static var women: [Product] { 80 | let data = [ 81 | "Shoes": [ 82 | "https://images.unsplash.com/photo-1519415943484-9fa1873496d4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2550&q=20", 83 | "https://images.unsplash.com/photo-1543163521-1bf539c55dd2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1600&q=20", 84 | "https://images.unsplash.com/photo-1515347619252-60a4bf4fff4f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2563&q=20", 85 | "https://images.unsplash.com/photo-1522315109300-78ce09fe6d37?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20" 86 | ], 87 | "Shirts": 88 | [ 89 | "https://images.unsplash.com/photo-1541101767792-f9b2b1c4f127?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1232&q=20", 90 | "https://images.unsplash.com/photo-1541101694594-8611136caf62?ixlib=rb-1.2.1&auto=format&fit=crop&w=1232&q=20", 91 | "https://images.unsplash.com/photo-1541101584841-db067cfbb494?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1232&q=20", 92 | ], 93 | "Jackets": 94 | [ 95 | "https://images.unsplash.com/photo-1573497491367-887b4895f9a7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 96 | "https://images.unsplash.com/photo-1573164713350-b14a82d3c15b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 97 | "https://images.unsplash.com/photo-1581109708418-50ffef26a08f?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 98 | "https://images.unsplash.com/photo-1581109708259-640d8f21663f?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 99 | "https://images.unsplash.com/photo-1592233548196-eca8244f470c?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20" 100 | ], 101 | "T-Shirts": 102 | [ 103 | "https://images.unsplash.com/photo-1578707800776-5cd6b01c9dcf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 104 | "https://images.unsplash.com/photo-1578789948226-ccbc6043295b?ixlib=rb-1.2.1&auto=format&fit=crop&w=1301&q=20", 105 | "https://images.unsplash.com/photo-1562615992-6289cfc36f2c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 106 | "https://images.unsplash.com/photo-1586102931834-b14a6c079331?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 107 | "https://images.unsplash.com/photo-1586102901518-ca0f178acb5f?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 108 | "https://images.unsplash.com/photo-1586102358078-9418f6b4808f?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20" 109 | ] 110 | ] 111 | 112 | return generate(from: data) 113 | } 114 | 115 | static var kids: [Product] { 116 | let data = [ 117 | "Shoes": [ 118 | "https://images.unsplash.com/photo-1515349541556-ef8cc276e382?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3582&q=20", 119 | "https://images.unsplash.com/photo-1573309463328-ec43614b3def?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 120 | "https://images.unsplash.com/photo-1573309463326-92397f7b730d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 121 | ], 122 | "Shirts": 123 | [ 124 | "https://images.unsplash.com/photo-1593052393678-d1c690c76071?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 125 | "https://images.unsplash.com/photo-1586026799068-60f878bccfce?ixlib=rb-1.2.1&auto=format&fit=crop&w=1230&q=20", 126 | "https://images.unsplash.com/photo-1586026799055-8b712d724d22?ixlib=rb-1.2.1&auto=format&fit=crop&w=1241&q=20", 127 | "https://images.unsplash.com/photo-1585979960500-ab6b717b1d42?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=80" 128 | ], 129 | "Jackets": 130 | [ 131 | "https://images.unsplash.com/photo-1585079183432-f028a6d73c4b?ixlib=rb-1.2.1&auto=format&fit=crop&w=2550&q=20", 132 | "https://images.unsplash.com/photo-1591851395349-6d8c2fe76e24?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1234&q=20", 133 | 134 | ], 135 | "T-Shirts": 136 | [ 137 | "https://images.unsplash.com/photo-1590815667477-ca82bcc1e775?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 138 | "https://images.unsplash.com/photo-1534774498201-97a162e50482?ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=20", 139 | "https://images.unsplash.com/photo-1534774517378-c7c29d6ed424?ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=20", 140 | ] 141 | ] 142 | 143 | return generate(from: data) 144 | } 145 | 146 | static func generate(from data: [String: [String]]) -> [Product] { 147 | 148 | let keys = Array(data.keys) 149 | let values = Array(data.values) 150 | 151 | return(1...100).map { i -> Product in 152 | 153 | let index = Int.random(in: 0.. PageController{ 40 | 41 | return PageController(viewControllers: data.pages.map({ 42 | 43 | UIHostingController(rootView: PageView(page: $0)) 44 | }), selectedIndex: .constant(nil)) 45 | 46 | } 47 | } 48 | 49 | struct HomeScreen_Previews: PreviewProvider { 50 | static var previews: some View { 51 | HomeScreen(category: .constant(Category.kids)) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ZaraApp/Screens/LoginScreen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginScreen.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct LoginScreen: View { 11 | var onDismiss = {} 12 | @State private var email = "" 13 | @State private var password = "" 14 | 15 | var body: some View { 16 | 17 | VStack { 18 | 19 | HStack { 20 | 21 | CloseButton(onDismiss: onDismiss) 22 | Spacer() 23 | } 24 | 25 | Spacer() 26 | 27 | VStack(spacing: 20) { 28 | 29 | VStack { 30 | 31 | TextField("Email", text: self.$email) 32 | 33 | Divider() 34 | } 35 | 36 | VStack { 37 | 38 | SecureField("Password", text: self.$password) 39 | 40 | Divider() 41 | } 42 | 43 | FilledButton(text: "LOG IN", action: onDismiss) 44 | .frame(maxWidth: .infinity) 45 | .reverseBgColor() 46 | 47 | NakedButton(text: "Have you forgotten your password?") 48 | } 49 | 50 | Spacer() 51 | 52 | VStack { 53 | 54 | BorderedButton(text: "CHAT", action: {}) 55 | 56 | NakedButton(text: "Don't have an account? Register") 57 | } 58 | }.padding() 59 | } 60 | } 61 | 62 | struct LoginScreen_Previews: PreviewProvider { 63 | static var previews: some View { 64 | LoginScreen() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ZaraApp/Screens/ProductDetailScreen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PodcastDetailScreen.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | import Kingfisher 10 | 11 | struct ProductDetailScreen: View { 12 | 13 | var product: Product 14 | var onDismiss = {} 15 | 16 | @State private var progress: CGFloat = 1 17 | @State private var selectedIndex: Int? 18 | 19 | @Namespace private var animation 20 | 21 | private let foldedHeight: CGFloat = 300 22 | private let expandedHeight = Sizes.screenHeight - UIScreen.main.bounds.height * 0.22 23 | var body: some View { 24 | 25 | ZStack(alignment: .top) { 26 | 27 | createPagingController() 28 | 29 | if selectedIndex == nil { 30 | createCustomSheet() 31 | } else { 32 | createProductImageView() 33 | } 34 | 35 | createNavBarView() 36 | }.edgesIgnoringSafeArea(.all) 37 | .animation(.linear, value: selectedIndex) 38 | } 39 | 40 | fileprivate func createCustomSheet() -> some View { 41 | 42 | CustomSheet(progress: self.$progress, foldedHeight: foldedHeight, expandedHeight: expandedHeight) { 43 | 44 | ProductDetailContent(product: product) 45 | } 46 | } 47 | 48 | fileprivate func createProductImageView() -> ProductImageView { 49 | let images = product.images 50 | return ProductImageView(imageUrl: images[selectedIndex!], animation: animation) { 51 | 52 | 53 | self.selectedIndex = nil 54 | 55 | } 56 | } 57 | 58 | fileprivate func createPagingController() -> some View { 59 | PageController(viewControllers: 60 | product.images.map({ 61 | UIHostingController(rootView: 62 | ImagePageView(image: $0) 63 | .matchedGeometryEffect(id: $0, in: animation) 64 | )}), selectedIndex: self.$selectedIndex) 65 | } 66 | 67 | fileprivate func createNavBarView() -> some View { 68 | ClearNavBar(opacity: Double(1 - progress), onDismiss: onDismiss) 69 | .padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top) 70 | } 71 | 72 | 73 | } 74 | 75 | struct ProductDetailScreen_Previews: PreviewProvider { 76 | static var previews: some View { 77 | ProductDetailScreen(product: Product.kids.first!) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ZaraApp/Screens/ProductListScreen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProductListScreen.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ProductListScreen: View { 11 | 12 | @Binding var category: Category? 13 | 14 | @EnvironmentObject private var store: Store 15 | 16 | @State private var selectedProduct: Product? 17 | 18 | private let columns = [ 19 | 20 | GridItem(.adaptive(minimum: 150), spacing: 20) 21 | 22 | ] 23 | 24 | var body: some View { 25 | 26 | return ZStack(alignment: .top) { 27 | 28 | ScrollView { 29 | 30 | createGrid() 31 | }.padding(.top, Sizes.navBarHeight) 32 | .padding(.horizontal, 15) 33 | 34 | createNavBar() 35 | 36 | }.onAppear(perform: { 37 | 38 | setProducts() 39 | }).fullScreenCover(item: $selectedProduct, content: { 40 | 41 | 42 | ProductDetailScreen(product: $0) { 43 | 44 | self.selectedProduct = nil 45 | } 46 | }) 47 | } 48 | 49 | fileprivate func createGrid() -> LazyVGrid> { 50 | 51 | LazyVGrid(columns: columns, alignment: .center, spacing: 40) { 52 | ForEach(store.state.products) { product in 53 | 54 | createProductItemView(product) 55 | } 56 | } 57 | } 58 | 59 | fileprivate func createNavBar() -> NavBar { 60 | 61 | return NavBar(title: "NEW IN ") { 62 | 63 | category = nil 64 | 65 | } onFilter: { 66 | 67 | 68 | } 69 | } 70 | 71 | fileprivate func setProducts() { 72 | 73 | guard let cat = self.category else { return } 74 | 75 | switch cat { 76 | 77 | case.men: 78 | store.dispatch(.addProducts(Product.men)) 79 | case.women: 80 | store.dispatch(.addProducts(Product.women)) 81 | case.kids: 82 | store.dispatch(.addProducts(Product.kids)) 83 | } 84 | } 85 | 86 | fileprivate func createProductItemView(_ product: Product) -> ProductItemView { 87 | 88 | return ProductItemView(product: product) { 89 | 90 | selectedProduct = product 91 | 92 | } bookmark: { 93 | 94 | store.dispatch(.bookmark(product)) 95 | } 96 | } 97 | } 98 | 99 | struct ProductListScreen_Previews: PreviewProvider { 100 | static var previews: some View { 101 | ProductListScreen(category: .constant(Category.kids)).environmentObject(Store()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ZaraApp/UIKit/CollectionCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionCell.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | class CollectionCell: UICollectionViewCell { 12 | 13 | static let reusedId: String = "CollectionCell" 14 | 15 | 16 | var viewController: UIViewController? { 17 | 18 | didSet { 19 | 20 | if let viewController = self.viewController { 21 | 22 | setUpCell(viewController) 23 | } 24 | } 25 | } 26 | 27 | override init(frame: CGRect) { 28 | super.init(frame: frame) 29 | if let viewController = self.viewController { 30 | setUpCell(viewController) 31 | } 32 | } 33 | required init?(coder: NSCoder) { 34 | super.init(coder: coder) 35 | } 36 | 37 | private func setUpCell(_ viewController: UIViewController) { 38 | 39 | 40 | guard let view = viewController.view else { 41 | 42 | return 43 | } 44 | 45 | view.translatesAutoresizingMaskIntoConstraints = false 46 | view.backgroundColor = .clear 47 | self.addSubview(view) 48 | 49 | 50 | NSLayoutConstraint.activate([ 51 | 52 | view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), 53 | view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), 54 | view.topAnchor.constraint(equalTo: contentView.topAnchor), 55 | view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) 56 | 57 | 58 | ]) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ZaraApp/UIKit/CollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import UIKit 11 | 12 | struct CollectionView: UIViewRepresentable { 13 | 14 | var controller: [UIViewController] 15 | 16 | @Binding var currentPage: Int 17 | @Binding var selectedIndex: Int? 18 | 19 | func makeUIView(context: Context) -> UICollectionView { 20 | 21 | let layout = UICollectionViewFlowLayout() 22 | let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) 23 | collectionView.backgroundColor = .clear 24 | collectionView.register(CollectionCell.self, forCellWithReuseIdentifier: CollectionCell.reusedId) 25 | collectionView.dataSource = context.coordinator 26 | collectionView.delegate = context.coordinator 27 | collectionView.isPagingEnabled = true 28 | collectionView.alwaysBounceVertical = false 29 | collectionView.showsVerticalScrollIndicator = true 30 | layout.minimumLineSpacing = 0 31 | 32 | return collectionView 33 | } 34 | 35 | func updateUIView(_ collectionView: UICollectionView, context: Context) { 36 | 37 | } 38 | 39 | func makeCoordinator() -> CollectionView.Coordinator { 40 | 41 | Coordinator(self) 42 | } 43 | 44 | class Coordinator: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 45 | 46 | var parent: CollectionView 47 | 48 | init(_ parent: CollectionView) { 49 | 50 | self.parent = parent 51 | } 52 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 53 | 54 | return parent.controller.count 55 | } 56 | 57 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 58 | if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionCell.reusedId, for: indexPath) as? CollectionCell { 59 | 60 | cell.viewController = parent.controller[indexPath.item] 61 | 62 | return cell 63 | } 64 | 65 | return UICollectionViewCell() 66 | } 67 | 68 | func collectionView(_ collectionView: UICollectionView, 69 | didEndDisplaying cell: UICollectionViewCell, 70 | forItemAt indexPath: IndexPath) { 71 | guard let index = collectionView.indexPathsForVisibleItems.first?.item else { 72 | return 73 | } 74 | self.parent.currentPage = index 75 | } 76 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 77 | self.parent.selectedIndex = indexPath.item 78 | } 79 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 80 | return CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ZaraApp/Utils/Sizes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sizes.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | struct Sizes { 12 | 13 | static var navBarHeight: CGFloat { 50 } 14 | static var tabHeight: CGFloat { UIScreen.main.bounds.width * 0.15} 15 | static var screenWidth = UIScreen.main.bounds.width 16 | static var screenHeight = UIScreen.main.bounds.height 17 | } 18 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/ArrowButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrowButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ArrowButtton: View { 11 | 12 | var text: String 13 | var action = {} 14 | 15 | var body: some View { 16 | Button(action: action, label: { 17 | HStack { 18 | Image(systemName: "arrowtriangle.right.fill") 19 | .font(.system(size: 10, weight: Font.Weight.light, design: Font.Design.default)) 20 | .foregroundColor(.text) 21 | 22 | Text(text).font(.system(size: 15, weight: Font.Weight.light, design: Font.Design.default)) 23 | .foregroundColor(.text) 24 | } 25 | }) 26 | } 27 | } 28 | 29 | struct ArrowButtton_Previews: PreviewProvider { 30 | static var previews: some View { 31 | ArrowButtton(text: "COMPOSITION AND CARE") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/BorderedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BorderedButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct BorderedButton: View { 11 | var text: String 12 | var action = {} 13 | var body: some View { 14 | 15 | Button(action: action, label: { 16 | 17 | Text(text) 18 | .boldFont() 19 | .textColor() 20 | .padding(.horizontal, 30) 21 | .padding(.vertical, 10) 22 | .border(Color.text, width: 1) 23 | }) 24 | } 25 | } 26 | 27 | struct BorderedButton_Previews: PreviewProvider { 28 | static var previews: some View { 29 | BorderedButton(text: "ADD") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/CloseButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CloseButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CloseButton: View { 11 | 12 | var onDismiss = {} 13 | 14 | var body: some View { 15 | 16 | Button(action: onDismiss, label: { 17 | 18 | Image(systemName: "xmark") 19 | .thinFont() 20 | .textColor() 21 | }) 22 | } 23 | } 24 | 25 | struct CloseButton_Previews: PreviewProvider { 26 | static var previews: some View { 27 | CloseButton() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/FilledButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilledButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FilledButton: View { 11 | var text: String 12 | var action = {} 13 | var body: some View { 14 | 15 | Button(action: action, label: { 16 | 17 | Text(text) 18 | .boldFont() 19 | .reverseTextColor() 20 | .padding(.horizontal, 30) 21 | .padding(.vertical, 10) 22 | }) 23 | 24 | } 25 | } 26 | 27 | struct FilledButton_Previews: PreviewProvider { 28 | static var previews: some View { 29 | FilledButton(text: "LOG IN") 30 | .reverseBgColor() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/LargeNakedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LargeNakedButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct LargeNakedButton: View { 11 | var text: String 12 | var action = { } 13 | var body: some View { 14 | Text(text) 15 | .font(.system(size: 30, weight: Font.Weight.black, design: Font.Design.default)) 16 | .foregroundColor(.text) 17 | .frame(maxWidth: .infinity, alignment: .leading) 18 | } 19 | } 20 | 21 | struct LargeNakedButton_Previews: PreviewProvider { 22 | static var previews: some View { 23 | LargeNakedButton(text: "MY INFORMATION") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/NakedButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NakedButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NakedButton: View { 11 | var text: String 12 | var alignment: Alignment = .center 13 | var action = {} 14 | 15 | var body: some View { 16 | 17 | Button(action: action, label: { 18 | 19 | Text(text) 20 | .lightFont() 21 | .textColor() 22 | .padding(.vertical, 10) 23 | .frame(maxWidth: .infinity, alignment: alignment) 24 | }) 25 | } 26 | } 27 | 28 | struct NakedButton_Previews: PreviewProvider { 29 | static var previews: some View { 30 | NakedButton(text: "Have you forgotten your password?") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ZaraApp/Views/Buttons/iconButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // iconButton.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct iconButton: View { 11 | var icon: String 12 | var action = { } 13 | var body: some View { 14 | 15 | Button(action: action, label: { 16 | 17 | Image(systemName: icon) 18 | .lightFont() 19 | .textColor() 20 | }) 21 | } 22 | } 23 | 24 | struct iconButton_Previews: PreviewProvider { 25 | static var previews: some View { 26 | iconButton(icon: "square.and.arrow.up") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ZaraApp/Views/ClearNavBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClearNavBar.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ClearNavBar: View { 11 | var opacity: Double 12 | var onDismiss = {} 13 | var body: some View { 14 | 15 | HStack { 16 | 17 | Button(action: onDismiss, label: { 18 | 19 | Image(systemName: "xmark") 20 | .font(.system(size: 25, weight: Font.Weight.light, design: Font.Design.default)) 21 | .foregroundColor(.gray) 22 | .padding(10) 23 | 24 | }) 25 | 26 | Spacer() 27 | 28 | 29 | }.padding(.horizontal, 20) 30 | } 31 | } 32 | 33 | struct ClearNavBar_Previews: PreviewProvider { 34 | static var previews: some View { 35 | ClearNavBar(opacity: 1) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ZaraApp/Views/CustomSheet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomSheet.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 04/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CustomSheet: View { 11 | 12 | enum SheetState { 13 | 14 | case expanded 15 | case folded 16 | 17 | } 18 | 19 | @State private var yOffset: CGFloat = Sizes.screenHeight 20 | @State private var sheetState: SheetState = .folded 21 | 22 | @Binding var progress: CGFloat 23 | 24 | var foldedHeight: CGFloat 25 | var expandedHeight: CGFloat 26 | 27 | var content: (() -> Content) 28 | 29 | init(progress: Binding, foldedHeight: CGFloat = 400, expandedHeight: CGFloat = Sizes.screenWidth , @ViewBuilder content: @escaping(() -> Content)) { 30 | 31 | self._progress = progress 32 | self.content = content 33 | self.foldedHeight = foldedHeight 34 | self.expandedHeight = expandedHeight 35 | } 36 | 37 | var body: some View { 38 | 39 | Group { 40 | 41 | createContent() 42 | }.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) 43 | .onAppear(perform: { 44 | yOffset = deltaHeight() 45 | }) 46 | } 47 | 48 | fileprivate func createContent() -> some View { 49 | 50 | 51 | Color.background 52 | .overlay(content(), alignment: .top) 53 | .frame(height: expandedHeight, alignment: .bottom) 54 | .offset(x: 0, y: yOffset) 55 | .gesture(DragGesture().onChanged({ drag in 56 | 57 | HandleOnDrag(drag) 58 | }).onEnded { drag in 59 | 60 | handleOnEnded(drag) 61 | } 62 | 63 | ).animation(.easeInOut, value: self.sheetState) 64 | } 65 | 66 | private func HandleOnDrag(_ drag: DragGesture.Value){ 67 | 68 | self.yOffset = sheetState == .expanded ? max(drag.translation.height, 0) : min(drag.location.y, deltaHeight()) 69 | 70 | self.progress = yOffset / deltaHeight() 71 | 72 | } 73 | 74 | private func handleOnEnded(_ drag: _ChangedGesture.Value) { 75 | 76 | switch sheetState { 77 | 78 | case.expanded: 79 | 80 | resetValues(for: drag.translation.height > foldedHeight ? .folded : .expanded) 81 | 82 | case .folded: 83 | resetValues(for: abs(drag.location.y) < deltaHeight() ? .expanded : .folded) 84 | } 85 | 86 | } 87 | 88 | private func resetValues(for state: SheetState) { 89 | 90 | self.yOffset = state == .folded ? deltaHeight() : 0 91 | self.sheetState = state 92 | self.progress = state == .folded ? 1 : 0 93 | } 94 | 95 | private func deltaHeight() -> CGFloat { 96 | 97 | expandedHeight - foldedHeight 98 | } 99 | } 100 | 101 | struct CustomSheet_Previews: PreviewProvider { 102 | static var previews: some View { 103 | CustomSheet(progress: .constant(0), foldedHeight: 200, expandedHeight: UIScreen.main.bounds.height - 200) { 104 | 105 | Text("This is a custom sheet") 106 | .frame(maxWidth: .infinity, maxHeight: .infinity) 107 | .background(Color.blue) 108 | .edgesIgnoringSafeArea(.all) 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /ZaraApp/Views/ImagePageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImagePageView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | import Kingfisher 10 | 11 | struct ImagePageView: View { 12 | var image: String 13 | private let screenWidth = Sizes.screenWidth 14 | private let screenHeight = Sizes.screenHeight 15 | 16 | var body: some View { 17 | 18 | URL(string: image).map { 19 | 20 | KFImage($0) 21 | .resizable() 22 | .aspectRatio(contentMode: .fill) 23 | .frame(width: screenWidth, height: screenHeight) 24 | 25 | } 26 | } 27 | } 28 | 29 | struct ImagePageView_Previews: PreviewProvider { 30 | static var previews: some View { 31 | ImagePageView(image: "zara-textured-check-shirt 3.JPG") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ZaraApp/Views/NavBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavBar.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NavBar: View { 11 | var title: String 12 | var onReturn = {} 13 | var onFilter = {} 14 | var body: some View { 15 | 16 | HStack { 17 | 18 | Button(action: onReturn, label: { 19 | Image(systemName: "arrow.left") 20 | .thinFont() 21 | }).frame(width: 40, alignment: .leading) 22 | 23 | Text(title) 24 | .font(.system(size: 18, weight: Font.Weight.bold, design: Font.Design.default)) 25 | .frame(maxWidth: .infinity, alignment: .center) 26 | 27 | Button(action: onFilter , label: { 28 | 29 | Text("FILTERS") 30 | .lightFont() 31 | }) 32 | }.padding(.horizontal) 33 | .padding(.bottom, 10) 34 | .textColor() 35 | .frame(height: Sizes.navBarHeight, alignment: .bottom) 36 | .bgColor() 37 | } 38 | } 39 | 40 | struct NavBar_Previews: PreviewProvider { 41 | static var previews: some View { 42 | NavBar(title: "NEW IN") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ZaraApp/Views/PageController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PageController.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PageController: View { 11 | 12 | var viewControllers: [UIHostingController] = [] 13 | @State var currentPage = 0 14 | @Binding var selectedIndex: Int? 15 | 16 | var body: some View { 17 | 18 | return ZStack(alignment: .trailing) { 19 | 20 | CollectionView(controller: viewControllers, currentPage: self.$currentPage, selectedIndex: self.$selectedIndex) 21 | 22 | VerticalPageIndicator(numberOfPages: viewControllers.count, selectedPageIndex: self.$currentPage).padding(.trailing, 10) 23 | } 24 | } 25 | } 26 | 27 | struct PageController_Previews: PreviewProvider { 28 | static var previews: some View { 29 | PageController(viewControllers: Page.data.map { UIHostingController(rootView: PageView(page: $0))}, selectedIndex: .constant(0)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ZaraApp/Views/PageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PageView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PageView: View { 11 | 12 | var page: Page 13 | 14 | var body: some View { 15 | VStack(spacing: 20){ 16 | 17 | Text(page.title) 18 | .multilineTextAlignment(.center) 19 | .font(.system(size: 50, weight: Font.Weight.black, design: Font.Design.default)) 20 | .textColor() 21 | .frame(width: Sizes.screenWidth * 0.95, alignment: .center) 22 | 23 | Text(page.description) 24 | .textColor() 25 | .multilineTextAlignment(.center) 26 | .frame(width: 300, alignment: .center) 27 | 28 | Text("View") 29 | .font(.system(size: 20, weight: Font.Weight.bold, design: Font.Design.default)) 30 | .textColor() 31 | .padding(.horizontal, 30) 32 | .padding(.vertical, 10) 33 | .border(Color.text, width: 1) 34 | 35 | 36 | 37 | }.frame(height: Sizes.screenHeight) 38 | .bgColor() 39 | .edgesIgnoringSafeArea(.all) 40 | } 41 | } 42 | 43 | struct PageView_Previews: PreviewProvider { 44 | static var previews: some View { 45 | PageView(page: Page.default) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ZaraApp/Views/ProductDetailContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProductDetailContent.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ProductDetailContent: View { 11 | 12 | var product: Product 13 | var body: some View { 14 | 15 | VStack(alignment: .leading, spacing: 30) { 16 | 17 | VStack(alignment: .leading, spacing: 10) { 18 | 19 | Text(product.title) 20 | .font(.system(size: 15, weight: Font.Weight.bold, design: Font.Design.default)) 21 | 22 | 23 | Text(product.price) 24 | .font(.system(size: 14, weight: Font.Weight.light, design: Font.Design.default)) 25 | 26 | HStack { 27 | 28 | BorderedButton(text: "ADD") 29 | 30 | Spacer() 31 | 32 | HStack(spacing: 20) { 33 | 34 | iconButton(icon: "square.and.arrow.up") { 35 | 36 | 37 | } 38 | iconButton(icon: "bookmark") { 39 | 40 | 41 | } 42 | iconButton(icon: "bag") { 43 | 44 | 45 | } 46 | } 47 | } 48 | } 49 | 50 | Text(product.description).font(.system(size: 14, weight: Font.Weight.light, design: Font.Design.default)) 51 | 52 | VStack(alignment: .leading, spacing: 20) { 53 | ArrowButtton(text: "COMPOSITION AND CARE") {} 54 | ArrowButtton(text: "IN-STORE AVAILABILITY") {} 55 | ArrowButtton(text: "SHIPPING AND RETURNS") {} 56 | ArrowButtton(text: "CAN WE HELP YOU") {} 57 | 58 | } 59 | }.padding(.all, 20) 60 | } 61 | } 62 | 63 | struct ProductDetailContent_Previews: PreviewProvider { 64 | static var previews: some View { 65 | ProductDetailContent(product: Product.kids.first!) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ZaraApp/Views/ProductImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProductImageView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 05/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | import Kingfisher 10 | 11 | struct ProductImageView: View { 12 | 13 | var imageUrl: String 14 | 15 | var animation: Namespace.ID 16 | var onDismissPreview = {} 17 | 18 | @State private var zoomLevel: CGFloat = 1 19 | @State private var offset: CGSize = .zero 20 | 21 | var body: some View { 22 | 23 | ImagePageView(image: imageUrl) 24 | .scaleEffect(self.zoomLevel) 25 | .offset(self.offset) 26 | 27 | .gesture(handleDragGesture()) 28 | .gesture(handleMagnificationGesture()) 29 | .onTapGesture(count: 2, perform: handleDoubleTapGesture) 30 | .onTapGesture(count: 1, perform: handleSingleTapGesture) 31 | .background(Color.background) 32 | .edgesIgnoringSafeArea(.all) 33 | .animation(.easeIn, value: self.zoomLevel) 34 | } 35 | 36 | private func handleDragGesture() -> _EndedGesture<_ChangedGesture> { 37 | 38 | return DragGesture() 39 | 40 | .onChanged({ value in 41 | if zoomLevel > 1 { 42 | 43 | self.offset = value.translation 44 | } 45 | }).onEnded( { value in 46 | withAnimation { 47 | self.offset = .zero 48 | } 49 | }) 50 | } 51 | 52 | private func handleMagnificationGesture() -> _EndedGesture<_ChangedGesture> { 53 | 54 | return MagnificationGesture().onChanged( { (value) in 55 | 56 | self.zoomLevel = value 57 | }).onEnded { value in 58 | if value < CGFloat(1) { 59 | 60 | self.zoomLevel = 1 61 | } 62 | } 63 | } 64 | 65 | private func handleSingleTapGesture() { 66 | 67 | if zoomLevel == 1 { 68 | 69 | onDismissPreview() 70 | } 71 | } 72 | 73 | private func handleDoubleTapGesture() { 74 | 75 | if zoomLevel > 1 { 76 | 77 | zoomLevel = 1 78 | }else { 79 | 80 | zoomLevel = 2 81 | } 82 | } 83 | } 84 | 85 | struct ProductImageView_Previews: PreviewProvider { 86 | 87 | @Namespace static var animation 88 | static var previews: some View { 89 | ProductImageView(imageUrl: "", animation: animation) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ZaraApp/Views/ProductItemView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProductItemView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | import Kingfisher 10 | 11 | struct ProductItemView: View { 12 | 13 | var product: Product 14 | var showDetail = {} 15 | var bookmark = {} 16 | 17 | var body: some View { 18 | 19 | VStack { 20 | 21 | KFImage(URL(string: product.mainImage)!) 22 | .resizable() 23 | .scaledToFill() 24 | .frame(width: (Sizes.screenWidth / 2 - 25), height: 250) 25 | .clipped() 26 | .onTapGesture(perform: showDetail) 27 | 28 | VStack(alignment: .leading) { 29 | 30 | Text(product.title) 31 | .lightFont() 32 | .lineLimit(1) 33 | 34 | HStack { 35 | 36 | Text(product.price) 37 | .lightFont() 38 | 39 | Spacer() 40 | Button(action: 41 | 42 | bookmark 43 | 44 | ,label: { 45 | 46 | Image(systemName: "bookmark") 47 | .lightFont() 48 | .textColor() 49 | }) 50 | } 51 | } 52 | }.padding(.horizontal) 53 | } 54 | } 55 | 56 | struct ProductItemView_Previews: PreviewProvider { 57 | static var previews: some View { 58 | ProductItemView(product: Product.men.first!) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ZaraApp/Views/TabBarView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabBarView.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TabBarView: View { 11 | 12 | @Binding var tab: Tab? 13 | 14 | var body: some View { 15 | 16 | HStack { 17 | 18 | Button(action: { 19 | 20 | onSelected(.search) 21 | }, label: { 22 | 23 | Image(systemName: "magnifyingglass") 24 | .thinFont() 25 | .frame(maxWidth: .infinity) 26 | }) 27 | 28 | Button(action: { 29 | 30 | onSelected(.bookmark) 31 | }, label: { 32 | 33 | Image(systemName: "bookmark") 34 | .thinFont() 35 | .frame(maxWidth: .infinity) 36 | }) 37 | 38 | Button(action: { 39 | 40 | onSelected(.menu) 41 | }, label: { 42 | 43 | Text("MENU") 44 | .thinFont() 45 | .frame(maxWidth: .infinity) 46 | }) 47 | 48 | Button(action: { 49 | 50 | onSelected(.profile) 51 | }, label: { 52 | 53 | Image(systemName: "person") 54 | .thinFont() 55 | .frame(maxWidth: .infinity) 56 | }) 57 | 58 | Button(action: { 59 | 60 | onSelected(.cart) 61 | 62 | }, label: { 63 | 64 | Image(systemName: "bag") 65 | .thinFont() 66 | .overlay( 67 | Text("9+").font(.system(size: 7, weight: Font.Weight.light, design: Font.Design.default)) 68 | .padding(.top, 2), alignment: .center) 69 | .frame(maxWidth: .infinity) 70 | }) 71 | 72 | }.frame(maxWidth: .infinity, maxHeight: Sizes.tabHeight, alignment: .top) 73 | .textColor() 74 | .bgColor() 75 | 76 | } 77 | 78 | func onSelected(_ tab: Tab) { 79 | 80 | self.tab = tab 81 | } 82 | } 83 | 84 | struct TabBarView_Previews: PreviewProvider { 85 | static var previews: some View { 86 | TabBarView(tab: .constant(.bookmark)) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ZaraApp/Views/TabIndicator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabIndicator.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TabIndicator: View { 11 | 12 | var category: Category 13 | 14 | var body: some View { 15 | 16 | HStack { 17 | 18 | ForEach(0.. some View { 14 | 15 | self.font(.system(size: 20, weight: Font.Weight.thin, design: Font.Design.default)) 16 | } 17 | 18 | func lightFont() -> some View { 19 | 20 | self.font(.system(size: 12, weight: Font.Weight.light, design: Font.Design.default)) 21 | } 22 | 23 | func boldFont() -> some View { 24 | 25 | self.font(.system(size: 15, weight: Font.Weight.bold, design: Font.Design.default)) 26 | 27 | } 28 | 29 | func textColor() -> some View { 30 | 31 | self.foregroundColor(.text) 32 | } 33 | 34 | func reverseTextColor() -> some View { 35 | 36 | self.foregroundColor(Color.background) 37 | } 38 | 39 | func bgColor() -> some View { 40 | 41 | self.background(Color.background) 42 | } 43 | 44 | func reverseBgColor() -> some View { 45 | 46 | 47 | self.background(Color.text) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ZaraApp/ZaraAppApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZaraAppApp.swift 3 | // ZaraApp 4 | // 5 | // Created by Temiloluwa on 01/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct ZaraAppApp: App { 12 | @StateObject private var store = Store() 13 | var body: some Scene { 14 | WindowGroup { 15 | ContentView().environmentObject(store) 16 | } 17 | } 18 | } 19 | --------------------------------------------------------------------------------