├── DashboardUI.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── cwiles.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── DashboardUI ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── BottomGradient.colorset │ │ └── Contents.json │ ├── CakeStand.imageset │ │ ├── Contents.json │ │ └── cake-stand.png │ ├── Contents.json │ ├── Cookware.imageset │ │ ├── Contents.json │ │ └── cookware.png │ ├── Couch.imageset │ │ ├── Contents.json │ │ └── couch.png │ ├── DarkBlue.colorset │ │ └── Contents.json │ ├── LightBlue.colorset │ │ └── Contents.json │ ├── Orange.colorset │ │ └── Contents.json │ ├── OutdoorLight.imageset │ │ ├── Contents.json │ │ └── outdoor-light.png │ ├── Person1.imageset │ │ ├── Contents.json │ │ └── image-250nw-662171107.jpg │ ├── Person2.imageset │ │ ├── Contents.json │ │ └── image-250nw-613759379.jpg │ ├── Person3.imageset │ │ ├── Contents.json │ │ └── image-250nw-640011838.jpg │ ├── Profile.imageset │ │ ├── 1zUn5pXp_400x400.jpg │ │ └── Contents.json │ └── TopGradient.colorset │ │ └── Contents.json ├── BackgroundView.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── BuyerRowView.swift ├── ContentView.swift ├── DashboardView.swift ├── DetailProductBuyerView.swift ├── DetailView.swift ├── Extensions.swift ├── FilterMenuView.swift ├── HandleBarView.swift ├── Helpers.swift ├── Info.plist ├── LineView.swift ├── MenuView.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── ProductView.swift ├── SceneDelegate.swift └── StatsView.swift ├── README.md └── Screenshots ├── dashboard-closed.png └── dashboard-open.png /DashboardUI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 01450D8523FC3F760055D0B2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01450D8423FC3F760055D0B2 /* AppDelegate.swift */; }; 11 | 01450D8723FC3F760055D0B2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01450D8623FC3F760055D0B2 /* SceneDelegate.swift */; }; 12 | 01450D8923FC3F760055D0B2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01450D8823FC3F760055D0B2 /* ContentView.swift */; }; 13 | 01450D8B23FC3F770055D0B2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01450D8A23FC3F770055D0B2 /* Assets.xcassets */; }; 14 | 01450D8E23FC3F770055D0B2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01450D8D23FC3F770055D0B2 /* Preview Assets.xcassets */; }; 15 | 01450D9123FC3F770055D0B2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01450D8F23FC3F770055D0B2 /* LaunchScreen.storyboard */; }; 16 | 01665A8D24016AF300737792 /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01665A8C24016AF300737792 /* DashboardView.swift */; }; 17 | 01665AAF24016C4C00737792 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01665AAE24016C4C00737792 /* MenuView.swift */; }; 18 | 01665AB124016CC600737792 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01665AB024016CC600737792 /* StatsView.swift */; }; 19 | 01665AB524016D8800737792 /* BackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01665AB424016D8800737792 /* BackgroundView.swift */; }; 20 | 01799AF524061FF500F99C96 /* DetailProductBuyerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01799AF424061FF500F99C96 /* DetailProductBuyerView.swift */; }; 21 | 0189ACFF240956D8001591A9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 0189ACFE240956D8001591A9 /* README.md */; }; 22 | 01A0F09324056CE600F4D171 /* HandleBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A0F09224056CE600F4D171 /* HandleBarView.swift */; }; 23 | 01C262F624076AA90069EE9E /* FilterMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C262F524076AA90069EE9E /* FilterMenuView.swift */; }; 24 | 01CF825E24037F1500F03E79 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF825D24037F1500F03E79 /* Helpers.swift */; }; 25 | 01CF826024037FDC00F03E79 /* LineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF825F24037FDC00F03E79 /* LineView.swift */; }; 26 | 01CF82622403817400F03E79 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF82612403817400F03E79 /* Extensions.swift */; }; 27 | 01CF82642404271400F03E79 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF82632404271400F03E79 /* DetailView.swift */; }; 28 | 01F390E32404C11A00A155E8 /* BuyerRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F390E22404C11A00A155E8 /* BuyerRowView.swift */; }; 29 | 01F390E52404CF5A00A155E8 /* ProductView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F390E42404CF5A00A155E8 /* ProductView.swift */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 01450D8123FC3F760055D0B2 /* DashboardUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DashboardUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 01450D8423FC3F760055D0B2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 35 | 01450D8623FC3F760055D0B2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 36 | 01450D8823FC3F760055D0B2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 37 | 01450D8A23FC3F770055D0B2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 38 | 01450D8D23FC3F770055D0B2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 39 | 01450D9023FC3F770055D0B2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 40 | 01450D9223FC3F770055D0B2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 01665A8C24016AF300737792 /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = ""; }; 42 | 01665AAE24016C4C00737792 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; 43 | 01665AB024016CC600737792 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = ""; }; 44 | 01665AB424016D8800737792 /* BackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundView.swift; sourceTree = ""; }; 45 | 01799AF424061FF500F99C96 /* DetailProductBuyerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailProductBuyerView.swift; sourceTree = ""; }; 46 | 0189ACFE240956D8001591A9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 47 | 01A0F09224056CE600F4D171 /* HandleBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleBarView.swift; sourceTree = ""; }; 48 | 01C262F524076AA90069EE9E /* FilterMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterMenuView.swift; sourceTree = ""; }; 49 | 01CF825D24037F1500F03E79 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; 50 | 01CF825F24037FDC00F03E79 /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = ""; }; 51 | 01CF82612403817400F03E79 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 52 | 01CF82632404271400F03E79 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = ""; }; 53 | 01F390E22404C11A00A155E8 /* BuyerRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuyerRowView.swift; sourceTree = ""; }; 54 | 01F390E42404CF5A00A155E8 /* ProductView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductView.swift; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 01450D7E23FC3F760055D0B2 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 01450D7823FC3F760055D0B2 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 01450D8323FC3F760055D0B2 /* DashboardUI */, 72 | 01450D8223FC3F760055D0B2 /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 01450D8223FC3F760055D0B2 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 01450D8123FC3F760055D0B2 /* DashboardUI.app */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 01450D8323FC3F760055D0B2 /* DashboardUI */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 0189ACFE240956D8001591A9 /* README.md */, 88 | 01450D9223FC3F770055D0B2 /* Info.plist */, 89 | 01450D8423FC3F760055D0B2 /* AppDelegate.swift */, 90 | 01665AB424016D8800737792 /* BackgroundView.swift */, 91 | 01F390E22404C11A00A155E8 /* BuyerRowView.swift */, 92 | 01450D8823FC3F760055D0B2 /* ContentView.swift */, 93 | 01665A8C24016AF300737792 /* DashboardView.swift */, 94 | 01799AF424061FF500F99C96 /* DetailProductBuyerView.swift */, 95 | 01CF82632404271400F03E79 /* DetailView.swift */, 96 | 01CF82612403817400F03E79 /* Extensions.swift */, 97 | 01C262F524076AA90069EE9E /* FilterMenuView.swift */, 98 | 01A0F09224056CE600F4D171 /* HandleBarView.swift */, 99 | 01CF825D24037F1500F03E79 /* Helpers.swift */, 100 | 01CF825F24037FDC00F03E79 /* LineView.swift */, 101 | 01665AAE24016C4C00737792 /* MenuView.swift */, 102 | 01F390E42404CF5A00A155E8 /* ProductView.swift */, 103 | 01450D8623FC3F760055D0B2 /* SceneDelegate.swift */, 104 | 01665AB024016CC600737792 /* StatsView.swift */, 105 | 01450D8A23FC3F770055D0B2 /* Assets.xcassets */, 106 | 01450D8F23FC3F770055D0B2 /* LaunchScreen.storyboard */, 107 | 01450D8C23FC3F770055D0B2 /* Preview Content */, 108 | ); 109 | path = DashboardUI; 110 | sourceTree = ""; 111 | }; 112 | 01450D8C23FC3F770055D0B2 /* Preview Content */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 01450D8D23FC3F770055D0B2 /* Preview Assets.xcassets */, 116 | ); 117 | path = "Preview Content"; 118 | sourceTree = ""; 119 | }; 120 | /* End PBXGroup section */ 121 | 122 | /* Begin PBXNativeTarget section */ 123 | 01450D8023FC3F760055D0B2 /* DashboardUI */ = { 124 | isa = PBXNativeTarget; 125 | buildConfigurationList = 01450D9523FC3F770055D0B2 /* Build configuration list for PBXNativeTarget "DashboardUI" */; 126 | buildPhases = ( 127 | 01450D7D23FC3F760055D0B2 /* Sources */, 128 | 01450D7E23FC3F760055D0B2 /* Frameworks */, 129 | 01450D7F23FC3F760055D0B2 /* Resources */, 130 | ); 131 | buildRules = ( 132 | ); 133 | dependencies = ( 134 | ); 135 | name = DashboardUI; 136 | productName = DashboardUI; 137 | productReference = 01450D8123FC3F760055D0B2 /* DashboardUI.app */; 138 | productType = "com.apple.product-type.application"; 139 | }; 140 | /* End PBXNativeTarget section */ 141 | 142 | /* Begin PBXProject section */ 143 | 01450D7923FC3F760055D0B2 /* Project object */ = { 144 | isa = PBXProject; 145 | attributes = { 146 | LastSwiftUpdateCheck = 1130; 147 | LastUpgradeCheck = 1130; 148 | ORGANIZATIONNAME = "Cory D. Wiles"; 149 | TargetAttributes = { 150 | 01450D8023FC3F760055D0B2 = { 151 | CreatedOnToolsVersion = 11.3.1; 152 | }; 153 | }; 154 | }; 155 | buildConfigurationList = 01450D7C23FC3F760055D0B2 /* Build configuration list for PBXProject "DashboardUI" */; 156 | compatibilityVersion = "Xcode 9.3"; 157 | developmentRegion = en; 158 | hasScannedForEncodings = 0; 159 | knownRegions = ( 160 | en, 161 | Base, 162 | ); 163 | mainGroup = 01450D7823FC3F760055D0B2; 164 | productRefGroup = 01450D8223FC3F760055D0B2 /* Products */; 165 | projectDirPath = ""; 166 | projectRoot = ""; 167 | targets = ( 168 | 01450D8023FC3F760055D0B2 /* DashboardUI */, 169 | ); 170 | }; 171 | /* End PBXProject section */ 172 | 173 | /* Begin PBXResourcesBuildPhase section */ 174 | 01450D7F23FC3F760055D0B2 /* Resources */ = { 175 | isa = PBXResourcesBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | 01450D9123FC3F770055D0B2 /* LaunchScreen.storyboard in Resources */, 179 | 01450D8E23FC3F770055D0B2 /* Preview Assets.xcassets in Resources */, 180 | 0189ACFF240956D8001591A9 /* README.md in Resources */, 181 | 01450D8B23FC3F770055D0B2 /* Assets.xcassets in Resources */, 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | }; 185 | /* End PBXResourcesBuildPhase section */ 186 | 187 | /* Begin PBXSourcesBuildPhase section */ 188 | 01450D7D23FC3F760055D0B2 /* Sources */ = { 189 | isa = PBXSourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | 01665AAF24016C4C00737792 /* MenuView.swift in Sources */, 193 | 01450D8523FC3F760055D0B2 /* AppDelegate.swift in Sources */, 194 | 01665AB124016CC600737792 /* StatsView.swift in Sources */, 195 | 01F390E32404C11A00A155E8 /* BuyerRowView.swift in Sources */, 196 | 01CF825E24037F1500F03E79 /* Helpers.swift in Sources */, 197 | 01C262F624076AA90069EE9E /* FilterMenuView.swift in Sources */, 198 | 01F390E52404CF5A00A155E8 /* ProductView.swift in Sources */, 199 | 01665AB524016D8800737792 /* BackgroundView.swift in Sources */, 200 | 01CF82642404271400F03E79 /* DetailView.swift in Sources */, 201 | 01A0F09324056CE600F4D171 /* HandleBarView.swift in Sources */, 202 | 01CF82622403817400F03E79 /* Extensions.swift in Sources */, 203 | 01CF826024037FDC00F03E79 /* LineView.swift in Sources */, 204 | 01665A8D24016AF300737792 /* DashboardView.swift in Sources */, 205 | 01450D8723FC3F760055D0B2 /* SceneDelegate.swift in Sources */, 206 | 01450D8923FC3F760055D0B2 /* ContentView.swift in Sources */, 207 | 01799AF524061FF500F99C96 /* DetailProductBuyerView.swift in Sources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXSourcesBuildPhase section */ 212 | 213 | /* Begin PBXVariantGroup section */ 214 | 01450D8F23FC3F770055D0B2 /* LaunchScreen.storyboard */ = { 215 | isa = PBXVariantGroup; 216 | children = ( 217 | 01450D9023FC3F770055D0B2 /* Base */, 218 | ); 219 | name = LaunchScreen.storyboard; 220 | sourceTree = ""; 221 | }; 222 | /* End PBXVariantGroup section */ 223 | 224 | /* Begin XCBuildConfiguration section */ 225 | 01450D9323FC3F770055D0B2 /* Debug */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_ANALYZER_NONNULL = YES; 230 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 231 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 232 | CLANG_CXX_LIBRARY = "libc++"; 233 | CLANG_ENABLE_MODULES = YES; 234 | CLANG_ENABLE_OBJC_ARC = YES; 235 | CLANG_ENABLE_OBJC_WEAK = YES; 236 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 237 | CLANG_WARN_BOOL_CONVERSION = YES; 238 | CLANG_WARN_COMMA = YES; 239 | CLANG_WARN_CONSTANT_CONVERSION = YES; 240 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 241 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 242 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 243 | CLANG_WARN_EMPTY_BODY = YES; 244 | CLANG_WARN_ENUM_CONVERSION = YES; 245 | CLANG_WARN_INFINITE_RECURSION = YES; 246 | CLANG_WARN_INT_CONVERSION = YES; 247 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 248 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 249 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 251 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 252 | CLANG_WARN_STRICT_PROTOTYPES = YES; 253 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 254 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 255 | CLANG_WARN_UNREACHABLE_CODE = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | COPY_PHASE_STRIP = NO; 258 | DEBUG_INFORMATION_FORMAT = dwarf; 259 | ENABLE_STRICT_OBJC_MSGSEND = YES; 260 | ENABLE_TESTABILITY = YES; 261 | GCC_C_LANGUAGE_STANDARD = gnu11; 262 | GCC_DYNAMIC_NO_PIC = NO; 263 | GCC_NO_COMMON_BLOCKS = YES; 264 | GCC_OPTIMIZATION_LEVEL = 0; 265 | GCC_PREPROCESSOR_DEFINITIONS = ( 266 | "DEBUG=1", 267 | "$(inherited)", 268 | ); 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 276 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 277 | MTL_FAST_MATH = YES; 278 | ONLY_ACTIVE_ARCH = YES; 279 | SDKROOT = iphoneos; 280 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 281 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 282 | }; 283 | name = Debug; 284 | }; 285 | 01450D9423FC3F770055D0B2 /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_ANALYZER_NONNULL = YES; 290 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 291 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 292 | CLANG_CXX_LIBRARY = "libc++"; 293 | CLANG_ENABLE_MODULES = YES; 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_ENABLE_OBJC_WEAK = YES; 296 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 297 | CLANG_WARN_BOOL_CONVERSION = YES; 298 | CLANG_WARN_COMMA = YES; 299 | CLANG_WARN_CONSTANT_CONVERSION = YES; 300 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 301 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 302 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 303 | CLANG_WARN_EMPTY_BODY = YES; 304 | CLANG_WARN_ENUM_CONVERSION = YES; 305 | CLANG_WARN_INFINITE_RECURSION = YES; 306 | CLANG_WARN_INT_CONVERSION = YES; 307 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 308 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 309 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 310 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 311 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 312 | CLANG_WARN_STRICT_PROTOTYPES = YES; 313 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 314 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 315 | CLANG_WARN_UNREACHABLE_CODE = YES; 316 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 317 | COPY_PHASE_STRIP = NO; 318 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 319 | ENABLE_NS_ASSERTIONS = NO; 320 | ENABLE_STRICT_OBJC_MSGSEND = YES; 321 | GCC_C_LANGUAGE_STANDARD = gnu11; 322 | GCC_NO_COMMON_BLOCKS = YES; 323 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 324 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 325 | GCC_WARN_UNDECLARED_SELECTOR = YES; 326 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 327 | GCC_WARN_UNUSED_FUNCTION = YES; 328 | GCC_WARN_UNUSED_VARIABLE = YES; 329 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 330 | MTL_ENABLE_DEBUG_INFO = NO; 331 | MTL_FAST_MATH = YES; 332 | SDKROOT = iphoneos; 333 | SWIFT_COMPILATION_MODE = wholemodule; 334 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 335 | VALIDATE_PRODUCT = YES; 336 | }; 337 | name = Release; 338 | }; 339 | 01450D9623FC3F770055D0B2 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 343 | CODE_SIGN_STYLE = Automatic; 344 | DEVELOPMENT_ASSET_PATHS = "\"DashboardUI/Preview Content\""; 345 | DEVELOPMENT_TEAM = XM4VAKDQL9; 346 | ENABLE_PREVIEWS = YES; 347 | INFOPLIST_FILE = DashboardUI/Info.plist; 348 | LD_RUNPATH_SEARCH_PATHS = ( 349 | "$(inherited)", 350 | "@executable_path/Frameworks", 351 | ); 352 | PRODUCT_BUNDLE_IDENTIFIER = com.corywiles.DashboardUI; 353 | PRODUCT_NAME = "$(TARGET_NAME)"; 354 | SWIFT_VERSION = 5.0; 355 | TARGETED_DEVICE_FAMILY = 2; 356 | }; 357 | name = Debug; 358 | }; 359 | 01450D9723FC3F770055D0B2 /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | buildSettings = { 362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 363 | CODE_SIGN_STYLE = Automatic; 364 | DEVELOPMENT_ASSET_PATHS = "\"DashboardUI/Preview Content\""; 365 | DEVELOPMENT_TEAM = XM4VAKDQL9; 366 | ENABLE_PREVIEWS = YES; 367 | INFOPLIST_FILE = DashboardUI/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "@executable_path/Frameworks", 371 | ); 372 | PRODUCT_BUNDLE_IDENTIFIER = com.corywiles.DashboardUI; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | SWIFT_VERSION = 5.0; 375 | TARGETED_DEVICE_FAMILY = 2; 376 | }; 377 | name = Release; 378 | }; 379 | /* End XCBuildConfiguration section */ 380 | 381 | /* Begin XCConfigurationList section */ 382 | 01450D7C23FC3F760055D0B2 /* Build configuration list for PBXProject "DashboardUI" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | 01450D9323FC3F770055D0B2 /* Debug */, 386 | 01450D9423FC3F770055D0B2 /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | 01450D9523FC3F770055D0B2 /* Build configuration list for PBXNativeTarget "DashboardUI" */ = { 392 | isa = XCConfigurationList; 393 | buildConfigurations = ( 394 | 01450D9623FC3F770055D0B2 /* Debug */, 395 | 01450D9723FC3F770055D0B2 /* Release */, 396 | ); 397 | defaultConfigurationIsVisible = 0; 398 | defaultConfigurationName = Release; 399 | }; 400 | /* End XCConfigurationList section */ 401 | }; 402 | rootObject = 01450D7923FC3F760055D0B2 /* Project object */; 403 | } 404 | -------------------------------------------------------------------------------- /DashboardUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DashboardUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DashboardUI.xcodeproj/xcuserdata/cwiles.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /DashboardUI.xcodeproj/xcuserdata/cwiles.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DashboardUI.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /DashboardUI/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/18/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/BottomGradient.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xFF", 13 | "alpha" : "1.000", 14 | "blue" : "0x7F", 15 | "green" : "0xB4" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/CakeStand.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "cake-stand.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/CakeStand.imageset/cake-stand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/CakeStand.imageset/cake-stand.png -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Cookware.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "cookware.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Cookware.imageset/cookware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Cookware.imageset/cookware.png -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Couch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "couch.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Couch.imageset/couch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Couch.imageset/couch.png -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/DarkBlue.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0x23", 13 | "alpha" : "1.000", 14 | "blue" : "0x42", 15 | "green" : "0x2D" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/LightBlue.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xF6", 13 | "alpha" : "1.000", 14 | "blue" : "0xF9", 15 | "green" : "0xF8" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Orange.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xFF", 13 | "alpha" : "1.000", 14 | "blue" : "0x57", 15 | "green" : "0xA1" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/OutdoorLight.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "outdoor-light.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/OutdoorLight.imageset/outdoor-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/OutdoorLight.imageset/outdoor-light.png -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image-250nw-662171107.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person1.imageset/image-250nw-662171107.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Person1.imageset/image-250nw-662171107.jpg -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image-250nw-613759379.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person2.imageset/image-250nw-613759379.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Person2.imageset/image-250nw-613759379.jpg -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image-250nw-640011838.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Person3.imageset/image-250nw-640011838.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Person3.imageset/image-250nw-640011838.jpg -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Profile.imageset/1zUn5pXp_400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/DashboardUI/Assets.xcassets/Profile.imageset/1zUn5pXp_400x400.jpg -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/Profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1zUn5pXp_400x400.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DashboardUI/Assets.xcassets/TopGradient.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xE5", 13 | "alpha" : "1.000", 14 | "blue" : "0x2F", 15 | "green" : "0x35" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /DashboardUI/BackgroundView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BackgroundView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/22/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct BackgroundView: View { 12 | var body: some View { 13 | LinearGradient( 14 | gradient: 15 | Gradient( 16 | colors: [ 17 | Color("TopGradient"), 18 | Color("BottomGradient") 19 | ]), 20 | startPoint: .top, 21 | endPoint: .bottom 22 | ).edgesIgnoringSafeArea(.all) 23 | } 24 | } 25 | 26 | struct BackgroundView_Previews: PreviewProvider { 27 | static var previews: some View { 28 | BackgroundView() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DashboardUI/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /DashboardUI/BuyerRowView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BuyerRowView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/24/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct BuyerRowView: View { 12 | 13 | var image: String 14 | 15 | var name: String 16 | 17 | var body: some View { 18 | 19 | HStack(spacing: 20) { 20 | 21 | Image(self.image) 22 | .resizable() 23 | .aspectRatio(contentMode: .fill) 24 | .frame(width: 60, height: 60) 25 | .clipShape(Circle()) 26 | .overlay(Circle().stroke( 27 | LinearGradient(gradient: Gradient(colors: [gradientStart, gradientEnd]), 28 | startPoint: .top, 29 | endPoint: .bottom), 30 | lineWidth: 2.0) 31 | ) 32 | Text(self.name) 33 | .foregroundColor(.gray) 34 | .font(.system(.headline)) 35 | .bold() 36 | Spacer() 37 | } 38 | .padding() 39 | } 40 | } 41 | 42 | struct BuyerRowView_Previews: PreviewProvider { 43 | static var previews: some View { 44 | BuyerRowView(image: "Person2", name: "Cory Wiles") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /DashboardUI/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/18/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | let chartLabels: Array = [ 12 | "Mon", 13 | "Tue", 14 | "Wed", 15 | "Thur", 16 | "Fri" 17 | ] 18 | 19 | let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255) 20 | let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 20.0 / 255) 21 | let minDashboardWidth: CGFloat = 450.0 22 | 23 | enum DetailViewState { 24 | 25 | case opened 26 | case closed 27 | } 28 | 29 | enum DragState { 30 | 31 | case inactive 32 | case pressing 33 | case dragging(translation: CGSize) 34 | 35 | var translation: CGSize { 36 | switch self { 37 | case .inactive, .pressing: 38 | return .zero 39 | case .dragging(let translation): 40 | return translation 41 | } 42 | } 43 | 44 | var isDragging: Bool { 45 | switch self { 46 | case .pressing, .dragging: 47 | return true 48 | case .inactive: 49 | return false 50 | } 51 | } 52 | } 53 | 54 | struct ContentView: View { 55 | 56 | @State private var positionOffset: CGFloat = 0.0 57 | 58 | @State private var viewState: DetailViewState = .closed 59 | 60 | @GestureState private var dragState: DragState = .inactive 61 | 62 | @State private var activeIdx: Int = 0 63 | @State private var rects: [CGRect] = Array(repeating: CGRect(), count: 3) 64 | 65 | var body: some View { 66 | 67 | GeometryReader {reader in 68 | 69 | ZStack { 70 | 71 | BackgroundView() 72 | 73 | VStack { 74 | HStack { 75 | Image("Profile") 76 | .resizable() 77 | .frame(width: 60, height: 60) 78 | .clipShape(Circle()) 79 | .shadow(color: Color.black.opacity(0.8), radius: 10.0) 80 | .overlay(Circle().stroke(Color.white, lineWidth: 1)) 81 | .padding(.leading) 82 | Spacer() 83 | } 84 | HStack(alignment: .top) { 85 | 86 | MenuView() 87 | .padding(.trailing, 70.0) 88 | .padding(.top, 90.0) 89 | 90 | VStack(alignment: .leading) { 91 | 92 | Text("Dashboard") 93 | .font(.system(.largeTitle)).bold() 94 | .foregroundColor(.white) 95 | .padding(.bottom) 96 | 97 | FilterMenuView() 98 | .frame(width: 300.0) 99 | .padding(.bottom, 50.0) 100 | .coordinateSpace(name: "filterMenu") 101 | 102 | DashboardView() 103 | .frame(width: 400.0, height: 400.0) 104 | 105 | Text("Stats") 106 | .foregroundColor(.white) 107 | .font(.system(.title)).bold() 108 | .padding(.bottom) 109 | .padding(.top, 45.0) 110 | 111 | StatsView() 112 | } 113 | .alignmentGuide(.top) { $0[.top] + 80 } 114 | .frame(maxWidth: .infinity, 115 | maxHeight: .infinity, 116 | alignment: .topLeading) 117 | Spacer() 118 | } 119 | Spacer() 120 | } 121 | .padding(.top) 122 | 123 | DetailProductBuyerView(viewState: self.$viewState, 124 | positionOffset: self.$positionOffset) 125 | .frame(width: minDashboardWidth) 126 | .padding([.top, .bottom]) 127 | .offset(x: 128 | (reader.size.width - minDashboardWidth) + self.positionOffset 129 | ) 130 | .animation(.spring()) 131 | .onTapGesture { } 132 | .gesture( 133 | DragGesture().onChanged { value in 134 | 135 | if self.viewState == .closed && 136 | value.translation.width > -200 { 137 | 138 | self.positionOffset = value.translation.width 139 | } 140 | } 141 | .onEnded { value in 142 | 143 | switch self.viewState { 144 | 145 | case .closed: 146 | 147 | let threshold: CGFloat = -50.0 148 | 149 | if value.translation.width < threshold { 150 | 151 | self.positionOffset = -(minDashboardWidth - 50.0) 152 | self.viewState = .opened 153 | 154 | } else { 155 | 156 | self.positionOffset = 0.0 157 | } 158 | 159 | break 160 | case .opened: 161 | self.viewState = .closed 162 | break 163 | } 164 | } 165 | ) 166 | } 167 | } 168 | } 169 | } 170 | 171 | struct ContentView_Previews: PreviewProvider { 172 | static var previews: some View { 173 | ContentView() 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /DashboardUI/DashboardView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DashboardView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/22/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct DashboardView: View { 12 | 13 | var body: some View { 14 | 15 | GeometryReader{ reader in 16 | ZStack(alignment: .top) { 17 | 18 | RoundedRectangle(cornerRadius: 15.0) 19 | .foregroundColor(.white) 20 | 21 | VStack(alignment: .leading) { 22 | 23 | HStack(alignment: .top) { 24 | VStack(alignment: .leading) { 25 | Text("$1,394") 26 | .font(.system(.title)) 27 | .bold() 28 | Text("+10% compared to last week") 29 | .font(.system(.caption)) 30 | .foregroundColor(.gray) 31 | .frame(width: 150.0) 32 | } 33 | Spacer() 34 | Text("Weekly") 35 | .font(.system(.body)) 36 | .bold() 37 | } 38 | .padding([.top, .leading, .trailing], 25) 39 | 40 | VStack() { 41 | GeometryReader {reader in 42 | ZStack { 43 | Rectangle() 44 | .foregroundColor(.white) 45 | LineView(frame: CGRect(x: 0, 46 | y: 0, 47 | width: reader.size.width, 48 | height: reader.size.height)) 49 | } 50 | } 51 | HStack { 52 | 53 | ForEach(chartLabels, id: \.self) {label in 54 | Text(label) 55 | .frame(maxWidth: .infinity) 56 | } 57 | } 58 | .padding() 59 | .frame(maxWidth: .infinity) 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | struct DashboardView_Previews: PreviewProvider { 68 | static var previews: some View { 69 | DashboardView() 70 | .frame(width: 400, height: 400.0) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /DashboardUI/DetailProductBuyerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailProductBuyerView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/25/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct DetailProductBuyerView: View { 12 | 13 | @Binding var viewState: DetailViewState 14 | 15 | @Binding var positionOffset: CGFloat 16 | 17 | var body: some View { 18 | 19 | HStack { 20 | 21 | Spacer() 22 | HandleBarView() 23 | .padding(.trailing, 10.0) 24 | 25 | VStack { 26 | DetailView(viewState: self.$viewState, 27 | positionOffset: self.$positionOffset) 28 | Spacer() 29 | } 30 | .background(RoundedRectangle(cornerRadius: 25).fill(Color.white)) 31 | } 32 | } 33 | } 34 | 35 | struct DetailProductBuyerView_Previews: PreviewProvider { 36 | static var previews: some View { 37 | DetailProductBuyerView(viewState: .constant(.closed), positionOffset: .constant(0.0)) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DashboardUI/DetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/24/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct DetailView: View { 12 | 13 | @Binding var viewState: DetailViewState 14 | 15 | @Binding var positionOffset: CGFloat 16 | 17 | var body: some View { 18 | 19 | VStack(alignment: .leading) { 20 | 21 | HStack(alignment: .center) { 22 | 23 | Text("Popular Products") 24 | .font(.system(.title)) 25 | .bold() 26 | .foregroundColor(.black) 27 | .padding([.leading, .top], 20) 28 | 29 | Spacer() 30 | 31 | Image(systemName: "xmark") 32 | .font(.system(size: 16, weight: .medium)) 33 | .foregroundColor(.white) 34 | .frame(width: 30, height: 30) 35 | .background(Color.black) 36 | .clipShape(Circle()) 37 | .padding([.top, .trailing], 10.0) 38 | .onTapGesture { 39 | 40 | self.viewState = .closed 41 | self.positionOffset = 0.0 42 | } 43 | } 44 | 45 | ScrollView(.horizontal) { 46 | 47 | HStack(spacing: 20) { 48 | 49 | ProductView(image: "Couch", 50 | productName: "Amazing Couch", 51 | unitsSold: "986 Units Sold") 52 | 53 | ProductView(image: "Cookware", 54 | productName: "10 pc Cookware", 55 | unitsSold: "1,204 Units sold") 56 | 57 | ProductView(image: "OutdoorLight", 58 | productName: "Outdoor Lighting", 59 | unitsSold: "545 Units sold") 60 | 61 | ProductView(image: "CakeStand", 62 | productName: "3 tier Cake Stand", 63 | unitsSold: "334 Units Sold") 64 | } 65 | } 66 | .padding([.trailing, .leading]) 67 | 68 | Text("Loyal Buyers") 69 | .font(.system(.title)) 70 | .bold() 71 | .foregroundColor(.black) 72 | .padding(.top) 73 | .padding(.leading, 20) 74 | 75 | ScrollView { 76 | BuyerRowView(image: "Person1", name: "Erin Wiles") 77 | BuyerRowView(image: "Person2", name: "McKinna Wiles") 78 | BuyerRowView(image: "Person3", name: "Cory Wiles") 79 | } 80 | 81 | Spacer() 82 | } 83 | } 84 | } 85 | 86 | struct DetailView_Previews: PreviewProvider { 87 | static var previews: some View { 88 | DetailView(viewState: .constant(.opened), positionOffset: .constant(0.0)) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /DashboardUI/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/23/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftUI 12 | 13 | extension CGPoint { 14 | 15 | static func getMidPoint(point1: CGPoint, point2: CGPoint) -> CGPoint { 16 | 17 | return CGPoint( 18 | x: point1.x + (point2.x - point1.x) / 2, 19 | y: point1.y + (point2.y - point1.y) / 2 20 | ) 21 | } 22 | 23 | func dist(to: CGPoint) -> CGFloat { 24 | return sqrt((pow(self.x - to.x, 2) + pow(self.y - to.y, 2))) 25 | } 26 | 27 | static func midPointForPoints(p1: CGPoint, p2: CGPoint) -> CGPoint { 28 | return CGPoint(x: (p1.x + p2.x) / 2,y: (p1.y + p2.y) / 2) 29 | } 30 | 31 | static func controlPointForPoints(p1: CGPoint, p2: CGPoint) -> CGPoint { 32 | 33 | var controlPoint = CGPoint.midPointForPoints(p1:p1, p2:p2) 34 | let diffY = abs(p2.y - controlPoint.y) 35 | 36 | if p1.y < p2.y { 37 | controlPoint.y += diffY 38 | } else if p1.y > p2.y { 39 | controlPoint.y -= diffY 40 | } 41 | 42 | return controlPoint 43 | } 44 | 45 | func adding(x: CGFloat) -> CGPoint { 46 | return CGPoint(x: self.x + x, y: self.y) 47 | } 48 | 49 | func adding(y: CGFloat) -> CGPoint { 50 | return CGPoint(x: self.x, y: self.y + y) 51 | } 52 | } 53 | 54 | extension CGPath { 55 | 56 | var points: Array { 57 | 58 | var arrPoints: Array = [] 59 | 60 | /// applyWithBlock lets us examine each element of the CGPath, and decide what to do 61 | 62 | self.applyWithBlock { element in 63 | 64 | switch element.pointee.type { 65 | 66 | case .moveToPoint, .addLineToPoint: 67 | arrPoints.append(element.pointee.points.pointee) 68 | 69 | case .addQuadCurveToPoint: 70 | 71 | arrPoints.append(element.pointee.points.pointee) 72 | arrPoints.append(element.pointee.points.advanced(by: 1).pointee) 73 | 74 | case .addCurveToPoint: 75 | 76 | arrPoints.append(element.pointee.points.pointee) 77 | arrPoints.append(element.pointee.points.advanced(by: 1).pointee) 78 | arrPoints.append(element.pointee.points.advanced(by: 2).pointee) 79 | 80 | default: 81 | break 82 | } 83 | } 84 | 85 | return arrPoints 86 | } 87 | } 88 | 89 | extension Path { 90 | 91 | static func quadCurvedPathWithPoints(points: Array, step: CGPoint) -> Path { 92 | 93 | var path = Path() 94 | 95 | if points.count < 2 { 96 | return path 97 | } 98 | 99 | guard let offset = points.min() else { 100 | return path 101 | } 102 | 103 | var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y + 8) 104 | path.move(to: p1) 105 | 106 | for pointIndex in 1.., step: CGPoint) -> Path { 120 | 121 | var path = Path() 122 | 123 | if points.count < 2 { 124 | return path 125 | } 126 | 127 | guard let offset = points.min() else { 128 | return path 129 | } 130 | 131 | path.move(to: .zero) 132 | 133 | var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y + 8) 134 | path.addLine(to: p1) 135 | 136 | for pointIndex in 1.. [MyTextPreferenceData]) { 26 | 27 | value.append(contentsOf: nextValue()) 28 | } 29 | } 30 | 31 | struct MenuItemView: View { 32 | 33 | @Binding var activeMonth: Int 34 | 35 | let label: String 36 | 37 | let idx: Int 38 | 39 | var body: some View { 40 | 41 | Text(label) 42 | .padding(10) 43 | .background(MyPreferenceViewSetter(idx: idx)) 44 | .foregroundColor(.white) 45 | .font(.system(.body)) 46 | .onTapGesture { 47 | self.activeMonth = self.idx 48 | } 49 | } 50 | } 51 | 52 | struct MyPreferenceViewSetter: View { 53 | 54 | let idx: Int 55 | 56 | var body: some View { 57 | 58 | GeometryReader { geometry in 59 | Rectangle() 60 | .fill(Color.clear) 61 | .preference(key: MyTextPreferenceKey.self, 62 | value: [MyTextPreferenceData(viewIdx: self.idx, rect: geometry.frame(in: .named("filterMenu")))]) 63 | } 64 | } 65 | } 66 | 67 | struct FilterMenuView: View { 68 | 69 | @State private var activeIdx: Int = 0 70 | @State private var rects: Array = Array(repeating: CGRect(), 71 | count: 3) 72 | 73 | var body: some View { 74 | 75 | VStack(alignment: .leading, spacing: 20.0) { 76 | 77 | HStack(spacing: 20.0) { 78 | 79 | MenuItemView(activeMonth: $activeIdx, label: "Sales", idx: 0) 80 | MenuItemView(activeMonth: $activeIdx, label: "Earnings", idx: 1) 81 | MenuItemView(activeMonth: $activeIdx, label: "Revenue", idx: 2) 82 | } 83 | .onPreferenceChange(MyTextPreferenceKey.self) { preferences in 84 | for p in preferences { 85 | self.rects[p.viewIdx] = p.rect 86 | } 87 | } 88 | 89 | ZStack(alignment: .leading) { 90 | 91 | Rectangle() 92 | .frame(height: 2.0) 93 | .foregroundColor(.white) 94 | .opacity(0.15) 95 | Rectangle() 96 | .frame(width: self.rects[self.activeIdx].width, height: 4.0) 97 | .foregroundColor(.white) 98 | .offset(x: self.rects[activeIdx].minX) 99 | .animation(.spring()) 100 | } 101 | } 102 | } 103 | } 104 | 105 | struct FilterMenuView_Previews: PreviewProvider { 106 | static var previews: some View { 107 | FilterMenuView() 108 | .background(Color.red) 109 | .frame(width: 300.0) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /DashboardUI/HandleBarView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HandleBarView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/25/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct HandleBarView: View { 12 | 13 | var body: some View { 14 | Rectangle() 15 | .frame(width: 5, height: 50) 16 | .foregroundColor(Color(.systemGray5)) 17 | .cornerRadius(10) 18 | } 19 | } 20 | 21 | struct HandleBarView_Previews: PreviewProvider { 22 | static var previews: some View { 23 | HandleBarView() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DashboardUI/Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Helpers.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/23/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | func midPointForPoints(_ p1: CGPoint, p2: CGPoint) -> CGPoint { 13 | return CGPoint(x: (p1.x + p2.x) / 2, y: (p2.x + p2.y) / 2) 14 | } 15 | 16 | func controlPointForPoints(_ p1: CGPoint, p2: CGPoint) -> CGPoint { 17 | 18 | var controlPoint: CGPoint = midPointForPoints(p1, p2: p2) 19 | let diffY: CGFloat = abs(p2.y - controlPoint.y) 20 | 21 | if p1.y < p2.y { 22 | controlPoint.y += diffY 23 | } else if p1.y > p2.y { 24 | controlPoint.y -= diffY 25 | } 26 | 27 | return controlPoint 28 | } 29 | 30 | func quadCurvePathwithPoints(_ points: Array) -> UIBezierPath { 31 | 32 | let path: UIBezierPath = UIBezierPath() 33 | var firstPoint: CGPoint = points.first! 34 | 35 | path.move(to: firstPoint) 36 | 37 | if points.count == 2 { 38 | 39 | let p2: CGPoint = points[1] 40 | path.addLine(to: p2) 41 | 42 | return path 43 | } 44 | 45 | for point in points.dropFirst() { 46 | 47 | let p2: CGPoint = point 48 | 49 | let midPoint: CGPoint = midPointForPoints(firstPoint, p2: p2) 50 | 51 | path.addQuadCurve(to: midPoint, controlPoint: firstPoint) 52 | path.addQuadCurve(to: p2, controlPoint: controlPointForPoints(midPoint, p2: p2)) 53 | 54 | firstPoint = p2 55 | } 56 | 57 | return path 58 | } 59 | 60 | -------------------------------------------------------------------------------- /DashboardUI/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationLandscapeLeft 55 | UIInterfaceOrientationLandscapeRight 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /DashboardUI/LineView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LineView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/23/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | let data: Array = [ 12 | 56.0, 13 | 100.0, 14 | 86.0, 15 | 119.0, 16 | 141.0, 17 | 122.0, 18 | 65.0, 19 | 79.0, 20 | 100.0 21 | ] 22 | 23 | struct LineView: View { 24 | 25 | var frame: CGRect 26 | 27 | var padding: CGFloat = 10.0 28 | 29 | @State private var showFull: Bool = false 30 | 31 | private var stepWidth: CGFloat { 32 | 33 | if data.count < 2 { 34 | return 0 35 | } 36 | 37 | return frame.size.width / CGFloat(data.count-1) 38 | } 39 | 40 | private var stepHeight: CGFloat { 41 | 42 | let points: Array = data 43 | 44 | if let min = points.min(), let max = points.max(), min != max { 45 | 46 | if min <= 0 { 47 | return (frame.size.height - padding) / CGFloat(points.max()! - points.min()!) 48 | } else { 49 | return (frame.size.height - padding) / CGFloat(points.max()! + points.min()!) 50 | } 51 | } 52 | 53 | return 0 54 | } 55 | 56 | private var fullPath: Path { 57 | 58 | let points: Array = data 59 | return Path.quadCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight)) 60 | } 61 | 62 | private var dataPath: Path { 63 | 64 | let points: Array = Array(data.dropLast()) 65 | return Path.quadCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight)) 66 | } 67 | 68 | private var lastPoint: CGPoint { 69 | return self.dataPath.cgPath.points.last! 70 | } 71 | 72 | private var circleStartLastPoint: CGPoint { 73 | return self.fullPath.cgPath.points.last! 74 | } 75 | 76 | var body: some View { 77 | 78 | return GeometryReader {reader in 79 | 80 | ZStack { 81 | Rectangle() 82 | .foregroundColor(.white) 83 | 84 | self.fullPath 85 | .stroke(lineWidth: 8.0) 86 | .foregroundColor(.black).opacity(0.1) 87 | .rotationEffect(.degrees(180), anchor: .center) 88 | .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0)) 89 | .drawingGroup() 90 | 91 | self.dataPath 92 | .trim(from: 0, to: self.showFull ? 1.0 : 0) 93 | .stroke(Color("Orange"), lineWidth: 6) 94 | .rotationEffect(.degrees(180), anchor: .center) 95 | .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0)) 96 | .animation(.easeOut(duration: 1.2)) 97 | .onAppear { 98 | self.showFull = true 99 | } 100 | .onDisappear { 101 | self.showFull = false 102 | } 103 | .drawingGroup() 104 | 105 | Circle() 106 | .trim(from: 0, to: self.showFull ? 1.0 : 0) 107 | .fill(Color.white) 108 | .opacity(self.showFull ? 1 : 0) 109 | .overlay( 110 | Circle().stroke(Color("Orange"), lineWidth: 6) 111 | .opacity(self.showFull ? 1 : 0) 112 | ) 113 | .frame(width: 20.0, height: 20.0) 114 | .position(self.showFull ? self.lastPoint : self.circleStartLastPoint) 115 | .rotationEffect(.degrees(180), anchor: .center) 116 | .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0)) 117 | .animation(Animation.easeInOut(duration: 1.2).delay(0.0)) 118 | } 119 | } 120 | } 121 | } 122 | 123 | struct LineView_Previews: PreviewProvider { 124 | static var previews: some View { 125 | LineView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /DashboardUI/MenuView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/22/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct MenuView: View { 12 | 13 | var body: some View { 14 | 15 | VStack(spacing: 10.0) { 16 | ZStack { 17 | RoundedRectangle(cornerRadius: 15.0) 18 | .foregroundColor(.black).opacity(0.3) 19 | Image(systemName: "chart.pie.fill") 20 | .resizable() 21 | .frame(width: 24, height: 24) 22 | .foregroundColor(.white) 23 | } 24 | .frame(width: 96, height: 96) 25 | .offset(x: -15, y: 0) 26 | ZStack { 27 | RoundedRectangle(cornerRadius: 15.0) 28 | .foregroundColor(.black).opacity(0.0) 29 | Image(systemName: "folder.fill") 30 | .resizable() 31 | .frame(width: 24, height: 24) 32 | .foregroundColor(.white) 33 | .opacity(0.5) 34 | } 35 | .frame(width: 96, height: 96) 36 | .offset(x: -15, y: 0) 37 | ZStack { 38 | RoundedRectangle(cornerRadius: 15.0) 39 | .foregroundColor(.black).opacity(0.0) 40 | Image(systemName: "person.fill") 41 | .resizable() 42 | .frame(width: 24, height: 24) 43 | .foregroundColor(.white) 44 | .opacity(0.5) 45 | } 46 | .frame(width: 96, height: 96) 47 | .offset(x: -15, y: 0) 48 | ZStack { 49 | RoundedRectangle(cornerRadius: 15.0) 50 | .foregroundColor(.black).opacity(0.0) 51 | Image(systemName: "calendar") 52 | .resizable() 53 | .frame(width: 24, height: 24) 54 | .foregroundColor(.white) 55 | .opacity(0.5) 56 | } 57 | .frame(width: 96, height: 96) 58 | .offset(x: -15, y: 0) 59 | } 60 | } 61 | } 62 | 63 | struct MenuView_Previews: PreviewProvider { 64 | static var previews: some View { 65 | MenuView() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /DashboardUI/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DashboardUI/ProductView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProductView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/24/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ProductView: View { 12 | 13 | var image: String 14 | 15 | var productName: String 16 | 17 | var unitsSold: String 18 | 19 | var body: some View { 20 | 21 | VStack(alignment: .leading) { 22 | Image(self.image) 23 | .resizable() 24 | .aspectRatio(contentMode: .fill) 25 | .frame(width: 100, height: 100) 26 | .clipShape(Circle()) 27 | .overlay(Circle().stroke(Color.white, lineWidth: 5)) 28 | .shadow(radius: 10) 29 | .padding([.top, .bottom]) 30 | .padding(.leading, 5) 31 | Text(self.productName) 32 | .foregroundColor(Color("DarkBlue")) 33 | .font(.title) 34 | .bold() 35 | .cornerRadius(15.0) 36 | .padding(.bottom) 37 | Text(self.unitsSold) 38 | .foregroundColor(.gray) 39 | .font(.headline) 40 | .bold() 41 | .cornerRadius(15.0) 42 | Spacer() 43 | } 44 | .frame(width: 200, height: 330.0) 45 | .background(Color("LightBlue")) 46 | .cornerRadius(25.0) 47 | } 48 | } 49 | 50 | struct ProductView_Previews: PreviewProvider { 51 | 52 | static var previews: some View { 53 | ProductView(image: "OutdoorLight", productName: "Outdoor Lighting", unitsSold: "545 Units sold") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DashboardUI/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/18/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 21 | 22 | // Create the SwiftUI view that provides the window contents. 23 | let contentView = ContentView() 24 | 25 | // Use a UIHostingController as window root view controller. 26 | if let windowScene = scene as? UIWindowScene { 27 | let window = UIWindow(windowScene: windowScene) 28 | window.rootViewController = UIHostingController(rootView: contentView) 29 | self.window = window 30 | window.makeKeyAndVisible() 31 | } 32 | } 33 | 34 | func sceneDidDisconnect(_ scene: UIScene) { 35 | // Called as the scene is being released by the system. 36 | // This occurs shortly after the scene enters the background, or when its session is discarded. 37 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 38 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 39 | } 40 | 41 | func sceneDidBecomeActive(_ scene: UIScene) { 42 | // Called when the scene has moved from an inactive state to an active state. 43 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 44 | } 45 | 46 | func sceneWillResignActive(_ scene: UIScene) { 47 | // Called when the scene will move from an active state to an inactive state. 48 | // This may occur due to temporary interruptions (ex. an incoming phone call). 49 | } 50 | 51 | func sceneWillEnterForeground(_ scene: UIScene) { 52 | // Called as the scene transitions from the background to the foreground. 53 | // Use this method to undo the changes made on entering the background. 54 | } 55 | 56 | func sceneDidEnterBackground(_ scene: UIScene) { 57 | // Called as the scene transitions from the foreground to the background. 58 | // Use this method to save data, release shared resources, and store enough scene-specific state information 59 | // to restore the scene back to its current state. 60 | } 61 | 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /DashboardUI/StatsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatsView.swift 3 | // DashboardUI 4 | // 5 | // Created by Cory D. Wiles on 2/22/20. 6 | // Copyright © 2020 Cory D. Wiles. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct StatsView: View { 12 | var body: some View { 13 | 14 | HStack(spacing: 100.0) { 15 | VStack(alignment: .leading, spacing: 10) { 16 | Text("Total Earnings") 17 | .font(.system(.caption)) 18 | .opacity(0.6) 19 | Text("$1245") 20 | .font(.system(.body)).bold() 21 | } 22 | .foregroundColor(.white) 23 | VStack(alignment: .leading, spacing: 10) { 24 | Text("Product Sold") 25 | .font(.system(.caption)) 26 | .opacity(0.6) 27 | Text("899") 28 | .font(.system(.body)).bold() 29 | } 30 | .foregroundColor(.white) 31 | VStack(alignment: .leading, spacing: 10) { 32 | Text("Ratings") 33 | .font(.system(.caption)) 34 | .opacity(0.6) 35 | Text("73%") 36 | .font(.system(.body)).bold() 37 | } 38 | .foregroundColor(.white) 39 | } 40 | } 41 | } 42 | 43 | struct StatsView_Previews: PreviewProvider { 44 | static var previews: some View { 45 | StatsView() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # DashboardUI 3 | 4 | ## Inspiration 5 | 6 | * [https://dribbble.com/shots/6807868-Commerce-Dashboard-UI](https://dribbble.com/shots/6807868-Commerce-Dashboard-UI) by [Ghani Pradita](https://dribbble.com/ghanipradita) 7 | 8 | ## Post 9 | 10 | [Fun Times Creating a Dashboard with SwiftUI](https://medium.com/@kwylez/fun-times-creating-a-dashboard-with-swiftui-28b68f1ffb89) 11 | 12 | ### Animations and Interactions 13 | 14 | You can drag the detail screen to open, the chart path and circle come together from opposites axis and the filter menu "underline" will move to the origin and size of the selected 15 | menu item. 16 | 17 | ![Detail view closed](Screenshots/dashboard-closed.png) 18 | ![Detail view opened](Screenshots/dashboard-open.png) 19 | 20 | -------------------------------------------------------------------------------- /Screenshots/dashboard-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/Screenshots/dashboard-closed.png -------------------------------------------------------------------------------- /Screenshots/dashboard-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kwylez/DashboardUI/97b06eb242b97360ebb9b4c13aef9e095b4ac9d5/Screenshots/dashboard-open.png --------------------------------------------------------------------------------