├── AppStoreAnimation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── nguyen.van.quangf.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── nguyen.van.quangf.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── AppStoreAnimation ├── AppStoreAnimationApp.swift ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── BG.colorset │ │ └── Contents.json │ ├── Contents.json │ ├── logo1.imageset │ │ ├── 2.heic │ │ └── Contents.json │ ├── logo2.imageset │ │ ├── 5.heic │ │ └── Contents.json │ ├── post1.imageset │ │ ├── 1.jpeg │ │ └── Contents.json │ └── post2.imageset │ │ ├── 4.heic │ │ └── Contents.json ├── ContentView.swift ├── Model │ └── Today.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json └── View │ ├── CustomCorner.swift │ └── Home.swift └── README.md /AppStoreAnimation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 46EA7A5227FFDC88002862E8 /* AppStoreAnimationApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EA7A5127FFDC88002862E8 /* AppStoreAnimationApp.swift */; }; 11 | 46EA7A5427FFDC88002862E8 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EA7A5327FFDC88002862E8 /* ContentView.swift */; }; 12 | 46EA7A5627FFDC8D002862E8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46EA7A5527FFDC8D002862E8 /* Assets.xcassets */; }; 13 | 46EA7A5927FFDC8D002862E8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46EA7A5827FFDC8D002862E8 /* Preview Assets.xcassets */; }; 14 | 46EA7A6227FFDE00002862E8 /* Today.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EA7A6127FFDE00002862E8 /* Today.swift */; }; 15 | 46EA7A6427FFDF0F002862E8 /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EA7A6327FFDF0F002862E8 /* Home.swift */; }; 16 | 46EA7A6627FFE954002862E8 /* CustomCorner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46EA7A6527FFE954002862E8 /* CustomCorner.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 46EA7A4E27FFDC88002862E8 /* AppStoreAnimation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AppStoreAnimation.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 46EA7A5127FFDC88002862E8 /* AppStoreAnimationApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreAnimationApp.swift; sourceTree = ""; }; 22 | 46EA7A5327FFDC88002862E8 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 23 | 46EA7A5527FFDC8D002862E8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 46EA7A5827FFDC8D002862E8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 25 | 46EA7A6127FFDE00002862E8 /* Today.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Today.swift; sourceTree = ""; }; 26 | 46EA7A6327FFDF0F002862E8 /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = ""; }; 27 | 46EA7A6527FFE954002862E8 /* CustomCorner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCorner.swift; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 46EA7A4B27FFDC88002862E8 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 46EA7A4527FFDC88002862E8 = { 42 | isa = PBXGroup; 43 | children = ( 44 | 46EA7A5027FFDC88002862E8 /* AppStoreAnimation */, 45 | 46EA7A4F27FFDC88002862E8 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | 46EA7A4F27FFDC88002862E8 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 46EA7A4E27FFDC88002862E8 /* AppStoreAnimation.app */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | 46EA7A5027FFDC88002862E8 /* AppStoreAnimation */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 46EA7A6027FFDDF2002862E8 /* Model */, 61 | 46EA7A5F27FFDDEA002862E8 /* View */, 62 | 46EA7A5127FFDC88002862E8 /* AppStoreAnimationApp.swift */, 63 | 46EA7A5327FFDC88002862E8 /* ContentView.swift */, 64 | 46EA7A5527FFDC8D002862E8 /* Assets.xcassets */, 65 | 46EA7A5727FFDC8D002862E8 /* Preview Content */, 66 | ); 67 | path = AppStoreAnimation; 68 | sourceTree = ""; 69 | }; 70 | 46EA7A5727FFDC8D002862E8 /* Preview Content */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 46EA7A5827FFDC8D002862E8 /* Preview Assets.xcassets */, 74 | ); 75 | path = "Preview Content"; 76 | sourceTree = ""; 77 | }; 78 | 46EA7A5F27FFDDEA002862E8 /* View */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 46EA7A6327FFDF0F002862E8 /* Home.swift */, 82 | 46EA7A6527FFE954002862E8 /* CustomCorner.swift */, 83 | ); 84 | path = View; 85 | sourceTree = ""; 86 | }; 87 | 46EA7A6027FFDDF2002862E8 /* Model */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 46EA7A6127FFDE00002862E8 /* Today.swift */, 91 | ); 92 | path = Model; 93 | sourceTree = ""; 94 | }; 95 | /* End PBXGroup section */ 96 | 97 | /* Begin PBXNativeTarget section */ 98 | 46EA7A4D27FFDC88002862E8 /* AppStoreAnimation */ = { 99 | isa = PBXNativeTarget; 100 | buildConfigurationList = 46EA7A5C27FFDC8D002862E8 /* Build configuration list for PBXNativeTarget "AppStoreAnimation" */; 101 | buildPhases = ( 102 | 46EA7A4A27FFDC88002862E8 /* Sources */, 103 | 46EA7A4B27FFDC88002862E8 /* Frameworks */, 104 | 46EA7A4C27FFDC88002862E8 /* Resources */, 105 | ); 106 | buildRules = ( 107 | ); 108 | dependencies = ( 109 | ); 110 | name = AppStoreAnimation; 111 | productName = AppStoreAnimation; 112 | productReference = 46EA7A4E27FFDC88002862E8 /* AppStoreAnimation.app */; 113 | productType = "com.apple.product-type.application"; 114 | }; 115 | /* End PBXNativeTarget section */ 116 | 117 | /* Begin PBXProject section */ 118 | 46EA7A4627FFDC88002862E8 /* Project object */ = { 119 | isa = PBXProject; 120 | attributes = { 121 | BuildIndependentTargetsInParallel = 1; 122 | LastSwiftUpdateCheck = 1310; 123 | LastUpgradeCheck = 1310; 124 | TargetAttributes = { 125 | 46EA7A4D27FFDC88002862E8 = { 126 | CreatedOnToolsVersion = 13.1; 127 | }; 128 | }; 129 | }; 130 | buildConfigurationList = 46EA7A4927FFDC88002862E8 /* Build configuration list for PBXProject "AppStoreAnimation" */; 131 | compatibilityVersion = "Xcode 13.0"; 132 | developmentRegion = en; 133 | hasScannedForEncodings = 0; 134 | knownRegions = ( 135 | en, 136 | Base, 137 | ); 138 | mainGroup = 46EA7A4527FFDC88002862E8; 139 | productRefGroup = 46EA7A4F27FFDC88002862E8 /* Products */; 140 | projectDirPath = ""; 141 | projectRoot = ""; 142 | targets = ( 143 | 46EA7A4D27FFDC88002862E8 /* AppStoreAnimation */, 144 | ); 145 | }; 146 | /* End PBXProject section */ 147 | 148 | /* Begin PBXResourcesBuildPhase section */ 149 | 46EA7A4C27FFDC88002862E8 /* Resources */ = { 150 | isa = PBXResourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 46EA7A5927FFDC8D002862E8 /* Preview Assets.xcassets in Resources */, 154 | 46EA7A5627FFDC8D002862E8 /* Assets.xcassets in Resources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXResourcesBuildPhase section */ 159 | 160 | /* Begin PBXSourcesBuildPhase section */ 161 | 46EA7A4A27FFDC88002862E8 /* Sources */ = { 162 | isa = PBXSourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 46EA7A5427FFDC88002862E8 /* ContentView.swift in Sources */, 166 | 46EA7A6227FFDE00002862E8 /* Today.swift in Sources */, 167 | 46EA7A6427FFDF0F002862E8 /* Home.swift in Sources */, 168 | 46EA7A5227FFDC88002862E8 /* AppStoreAnimationApp.swift in Sources */, 169 | 46EA7A6627FFE954002862E8 /* CustomCorner.swift in Sources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXSourcesBuildPhase section */ 174 | 175 | /* Begin XCBuildConfiguration section */ 176 | 46EA7A5A27FFDC8D002862E8 /* Debug */ = { 177 | isa = XCBuildConfiguration; 178 | buildSettings = { 179 | ALWAYS_SEARCH_USER_PATHS = NO; 180 | CLANG_ANALYZER_NONNULL = YES; 181 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 182 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 183 | CLANG_CXX_LIBRARY = "libc++"; 184 | CLANG_ENABLE_MODULES = YES; 185 | CLANG_ENABLE_OBJC_ARC = YES; 186 | CLANG_ENABLE_OBJC_WEAK = YES; 187 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 188 | CLANG_WARN_BOOL_CONVERSION = YES; 189 | CLANG_WARN_COMMA = YES; 190 | CLANG_WARN_CONSTANT_CONVERSION = YES; 191 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 192 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 193 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INFINITE_RECURSION = YES; 197 | CLANG_WARN_INT_CONVERSION = YES; 198 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 200 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 202 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 203 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 204 | CLANG_WARN_STRICT_PROTOTYPES = YES; 205 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 206 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 207 | CLANG_WARN_UNREACHABLE_CODE = YES; 208 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 209 | COPY_PHASE_STRIP = NO; 210 | DEBUG_INFORMATION_FORMAT = dwarf; 211 | ENABLE_STRICT_OBJC_MSGSEND = YES; 212 | ENABLE_TESTABILITY = YES; 213 | GCC_C_LANGUAGE_STANDARD = gnu11; 214 | GCC_DYNAMIC_NO_PIC = NO; 215 | GCC_NO_COMMON_BLOCKS = YES; 216 | GCC_OPTIMIZATION_LEVEL = 0; 217 | GCC_PREPROCESSOR_DEFINITIONS = ( 218 | "DEBUG=1", 219 | "$(inherited)", 220 | ); 221 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 222 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 223 | GCC_WARN_UNDECLARED_SELECTOR = YES; 224 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 225 | GCC_WARN_UNUSED_FUNCTION = YES; 226 | GCC_WARN_UNUSED_VARIABLE = YES; 227 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 228 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 229 | MTL_FAST_MATH = YES; 230 | ONLY_ACTIVE_ARCH = YES; 231 | SDKROOT = iphoneos; 232 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 233 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 234 | }; 235 | name = Debug; 236 | }; 237 | 46EA7A5B27FFDC8D002862E8 /* Release */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ANALYZER_NONNULL = YES; 242 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_ENABLE_OBJC_WEAK = YES; 248 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 249 | CLANG_WARN_BOOL_CONVERSION = YES; 250 | CLANG_WARN_COMMA = YES; 251 | CLANG_WARN_CONSTANT_CONVERSION = YES; 252 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 254 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INFINITE_RECURSION = YES; 258 | CLANG_WARN_INT_CONVERSION = YES; 259 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 261 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 264 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 265 | CLANG_WARN_STRICT_PROTOTYPES = YES; 266 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 267 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 268 | CLANG_WARN_UNREACHABLE_CODE = YES; 269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 270 | COPY_PHASE_STRIP = NO; 271 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 272 | ENABLE_NS_ASSERTIONS = NO; 273 | ENABLE_STRICT_OBJC_MSGSEND = YES; 274 | GCC_C_LANGUAGE_STANDARD = gnu11; 275 | GCC_NO_COMMON_BLOCKS = YES; 276 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 277 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 278 | GCC_WARN_UNDECLARED_SELECTOR = YES; 279 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 280 | GCC_WARN_UNUSED_FUNCTION = YES; 281 | GCC_WARN_UNUSED_VARIABLE = YES; 282 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 283 | MTL_ENABLE_DEBUG_INFO = NO; 284 | MTL_FAST_MATH = YES; 285 | SDKROOT = iphoneos; 286 | SWIFT_COMPILATION_MODE = wholemodule; 287 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 288 | VALIDATE_PRODUCT = YES; 289 | }; 290 | name = Release; 291 | }; 292 | 46EA7A5D27FFDC8D002862E8 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 297 | CODE_SIGN_STYLE = Automatic; 298 | CURRENT_PROJECT_VERSION = 1; 299 | DEVELOPMENT_ASSET_PATHS = "\"AppStoreAnimation/Preview Content\""; 300 | ENABLE_PREVIEWS = YES; 301 | GENERATE_INFOPLIST_FILE = YES; 302 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 303 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 304 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 305 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 306 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 307 | LD_RUNPATH_SEARCH_PATHS = ( 308 | "$(inherited)", 309 | "@executable_path/Frameworks", 310 | ); 311 | MARKETING_VERSION = 1.0; 312 | PRODUCT_BUNDLE_IDENTIFIER = com.AppStoreAnimation; 313 | PRODUCT_NAME = "$(TARGET_NAME)"; 314 | SWIFT_EMIT_LOC_STRINGS = YES; 315 | SWIFT_VERSION = 5.0; 316 | TARGETED_DEVICE_FAMILY = "1,2"; 317 | }; 318 | name = Debug; 319 | }; 320 | 46EA7A5E27FFDC8D002862E8 /* Release */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 325 | CODE_SIGN_STYLE = Automatic; 326 | CURRENT_PROJECT_VERSION = 1; 327 | DEVELOPMENT_ASSET_PATHS = "\"AppStoreAnimation/Preview Content\""; 328 | ENABLE_PREVIEWS = YES; 329 | GENERATE_INFOPLIST_FILE = YES; 330 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 331 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 332 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 333 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 334 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 335 | LD_RUNPATH_SEARCH_PATHS = ( 336 | "$(inherited)", 337 | "@executable_path/Frameworks", 338 | ); 339 | MARKETING_VERSION = 1.0; 340 | PRODUCT_BUNDLE_IDENTIFIER = com.AppStoreAnimation; 341 | PRODUCT_NAME = "$(TARGET_NAME)"; 342 | SWIFT_EMIT_LOC_STRINGS = YES; 343 | SWIFT_VERSION = 5.0; 344 | TARGETED_DEVICE_FAMILY = "1,2"; 345 | }; 346 | name = Release; 347 | }; 348 | /* End XCBuildConfiguration section */ 349 | 350 | /* Begin XCConfigurationList section */ 351 | 46EA7A4927FFDC88002862E8 /* Build configuration list for PBXProject "AppStoreAnimation" */ = { 352 | isa = XCConfigurationList; 353 | buildConfigurations = ( 354 | 46EA7A5A27FFDC8D002862E8 /* Debug */, 355 | 46EA7A5B27FFDC8D002862E8 /* Release */, 356 | ); 357 | defaultConfigurationIsVisible = 0; 358 | defaultConfigurationName = Release; 359 | }; 360 | 46EA7A5C27FFDC8D002862E8 /* Build configuration list for PBXNativeTarget "AppStoreAnimation" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 46EA7A5D27FFDC8D002862E8 /* Debug */, 364 | 46EA7A5E27FFDC8D002862E8 /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | /* End XCConfigurationList section */ 370 | }; 371 | rootObject = 46EA7A4627FFDC88002862E8 /* Project object */; 372 | } 373 | -------------------------------------------------------------------------------- /AppStoreAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AppStoreAnimation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AppStoreAnimation.xcodeproj/project.xcworkspace/xcuserdata/nguyen.van.quangf.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheep-q/AppStoreAnimation/1109445535c25a3f6df6d5367527e7fc10151b6e/AppStoreAnimation.xcodeproj/project.xcworkspace/xcuserdata/nguyen.van.quangf.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /AppStoreAnimation.xcodeproj/xcuserdata/nguyen.van.quangf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /AppStoreAnimation.xcodeproj/xcuserdata/nguyen.van.quangf.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AppStoreAnimation.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /AppStoreAnimation/AppStoreAnimationApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppStoreAnimationApp.swift 3 | // AppStoreAnimation 4 | // 5 | // Created by nguyen.van.quangf on 08/04/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct AppStoreAnimationApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AppStoreAnimation/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 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/BG.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.162", 9 | "green" : "0.162", 10 | "red" : "0.162" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | }, 20 | "properties" : { 21 | "localizable" : true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/logo1.imageset/2.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheep-q/AppStoreAnimation/1109445535c25a3f6df6d5367527e7fc10151b6e/AppStoreAnimation/Assets.xcassets/logo1.imageset/2.heic -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/logo1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "2.heic", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/logo2.imageset/5.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheep-q/AppStoreAnimation/1109445535c25a3f6df6d5367527e7fc10151b6e/AppStoreAnimation/Assets.xcassets/logo2.imageset/5.heic -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/logo2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "5.heic", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/post1.imageset/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheep-q/AppStoreAnimation/1109445535c25a3f6df6d5367527e7fc10151b6e/AppStoreAnimation/Assets.xcassets/post1.imageset/1.jpeg -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/post1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "1.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/post2.imageset/4.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sheep-q/AppStoreAnimation/1109445535c25a3f6df6d5367527e7fc10151b6e/AppStoreAnimation/Assets.xcassets/post2.imageset/4.heic -------------------------------------------------------------------------------- /AppStoreAnimation/Assets.xcassets/post2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "4.heic", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AppStoreAnimation/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // AppStoreAnimation 4 | // 5 | // Created by nguyen.van.quangf on 08/04/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | Home() 13 | } 14 | } 15 | 16 | struct ContentView_Previews: PreviewProvider { 17 | static var previews: some View { 18 | ContentView() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AppStoreAnimation/Model/Today.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Today.swift 3 | // AppStoreAnimation 4 | // 5 | // Created by nguyen.van.quangf on 08/04/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Today: Identifiable { 11 | var id = UUID().uuidString 12 | var appName: String 13 | var appDescription: String 14 | var appLogo: String 15 | var bannerTitle: String 16 | var platformTitle: String 17 | var artwork: String 18 | } 19 | 20 | var todayItems: [Today] = [ 21 | Today(appName: "Tiiiiiii", appDescription: "Battle with friends onine", appLogo: "logo1", bannerTitle: "Smash your rivals in LEGO Brawls", platformTitle: "Apple Arcade", artwork: "post1"), 22 | 23 | Today(appName: "SheepofG", appDescription: "Smash your rivals in LEGO Brawls", appLogo: "logo2", bannerTitle: "Her birthday on 18/4/1999", platformTitle: "Apple Arcade", artwork: "post2") 24 | ] 25 | 26 | var dummyText = "On Halloween, Gotham City mayor Don Mitchell Jr. is murdered by a serial killer calling himself the Riddler. Billionaire Bruce Wayne, who has operated for two years as the vigilante Batman, investigates alongside the Gotham City Police Department (GCPD). Lieutenant James Gordon discovers that the Riddler left a message for Batman, but commissioner Pete Savage berates him for allowing a vigilante to enter the crime scene and forces Batman to leave. The Riddler kills Savage and leaves another message for Batman.\nBatman and Gordon discover that the Riddler left a thumb drive in Mitchell's car containing images of Mitchell with a woman, Annika, at the Iceberg Lounge, a nightclub operated by mobster Carmine Falcone's lieutenant Penguin. Batman questions the Penguin, who pleads ignorance, but notices that Selina Kyle, Annika's roommate and girlfriend, works there as a waitress. After Annika disappears, Batman sends Selina back to the Iceberg Lounge to search for answers. Through Selina, Batman discovers that Savage was on Falcone's payroll, as is district attorney Gil Colson. Selina shuts off communication when Batman presses her about her relationship with Falcone." 27 | -------------------------------------------------------------------------------- /AppStoreAnimation/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppStoreAnimation/View/CustomCorner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCorner.swift 3 | // AppStoreAnimation 4 | // 5 | // Created by nguyen.van.quangf on 08/04/2022. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | import SwiftUI 11 | 12 | struct CustomCorner: Shape { 13 | var corners: UIRectCorner 14 | var radius: CGFloat 15 | 16 | func path(in rect: CGRect) -> Path { 17 | let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) 18 | 19 | return Path(path.cgPath) 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /AppStoreAnimation/View/Home.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Home.swift 3 | // AppStoreAnimation 4 | // 5 | // Created by nguyen.van.quangf on 08/04/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct Home: View { 11 | 12 | // MARK: - animation properties 13 | @State var showDetailPage = false 14 | @State var currentItem: Today? 15 | 16 | // MARK: - Match Geometry effect 17 | @Namespace var animation 18 | 19 | // MARK: - Detail Animation 20 | @State var animateView = false 21 | @State var animateContent = false 22 | @State var scrollOffset: CGFloat = 0 23 | 24 | var body: some View { 25 | ScrollView(.vertical, showsIndicators: false) { 26 | VStack(spacing: 0) { 27 | HStack(alignment: .bottom) { 28 | VStack(alignment: .leading, spacing: 8) { 29 | Text("FRIDAY 8 APRIL") 30 | .font(.callout) 31 | .foregroundColor(.gray) 32 | 33 | Text("Today") 34 | .font(.largeTitle.bold()) 35 | } 36 | .frame(maxWidth: .infinity, alignment: .leading) 37 | 38 | Button { 39 | 40 | } label: { 41 | Image(systemName: "person.circle.fill") 42 | .font(.largeTitle) 43 | } 44 | 45 | } 46 | .padding(.horizontal) 47 | .padding(.bottom) 48 | .opacity(showDetailPage ? 0 : 1) 49 | 50 | ForEach (todayItems) { item in 51 | Button { 52 | withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.7, blendDuration: 0.7)) { 53 | currentItem = item 54 | showDetailPage = true 55 | } 56 | } label: { 57 | CardView(item: item) 58 | // For matched geometry effect we didn't applied padding 59 | // instead applyin scaling 60 | // approx scaling value to match padding 61 | .scaleEffect(currentItem?.id == item.id && showDetailPage ? 1 : 0.93) 62 | } 63 | .buttonStyle(ScaleButtonStyle()) 64 | .opacity(showDetailPage ? (currentItem?.id == item.id ? 1 : 0) : 1) 65 | } 66 | } 67 | .padding(.vertical) 68 | } 69 | .overlay(content: { 70 | if let currentItem = currentItem, showDetailPage { 71 | DetailView(item: currentItem) 72 | .ignoresSafeArea(.container, edges: .top) 73 | } 74 | }) 75 | .background(alignment: .top) { 76 | RoundedRectangle(cornerRadius: 15, style: .continuous) 77 | .fill(Color("BG")) 78 | .frame(height: animateView ? nil : 350, alignment: .top) 79 | .scaleEffect(animateView ? 1 : 0.9) 80 | .opacity(animateView ? 1 : 0) 81 | .ignoresSafeArea() 82 | } 83 | } 84 | 85 | // MARK: - CardView 86 | @ViewBuilder 87 | func CardView(item: Today) -> some View { 88 | VStack(alignment: .leading, spacing: 15) { 89 | ZStack(alignment: .topLeading) { 90 | // Banner Image 91 | GeometryReader { proxy in 92 | let size = proxy.size 93 | 94 | Image(item.artwork) 95 | .resizable() 96 | .aspectRatio(contentMode: .fill) 97 | .frame(width: size.width, height: size.height) 98 | .clipShape(CustomCorner(corners: [.topLeft, .topRight], radius: 15)) 99 | } 100 | .frame(height: 400) 101 | 102 | LinearGradient(colors: [ 103 | .black.opacity(0.5), 104 | .black.opacity(0.2), 105 | .clear 106 | ], startPoint: .top, endPoint: .bottom) 107 | 108 | VStack(alignment: .leading, spacing: 8) { 109 | Text(item.platformTitle.uppercased()) 110 | .font(.callout) 111 | .fontWeight(.semibold) 112 | 113 | Text(item.bannerTitle) 114 | .font(.largeTitle.bold()) 115 | .multilineTextAlignment(.leading) 116 | } 117 | .foregroundColor(.primary) 118 | .padding() 119 | .offset(y: currentItem?.id == item.id && animateView ? safeArea().top : 0) 120 | } 121 | 122 | HStack(spacing: 12) { 123 | Image(item.appLogo) 124 | .resizable() 125 | .aspectRatio(contentMode: .fill) 126 | .frame(width: 60, height: 60) 127 | .clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous)) 128 | 129 | VStack(alignment: .leading, spacing: 4) { 130 | Text(item.platformTitle.uppercased()) 131 | .font(.caption) 132 | .foregroundColor(.gray) 133 | 134 | Text(item.appName) 135 | .fontWeight(.bold) 136 | 137 | Text(item.appDescription) 138 | .font(.caption) 139 | .foregroundColor(.gray) 140 | } 141 | .foregroundColor(.primary) 142 | .frame(maxWidth: .infinity, alignment: .leading) 143 | 144 | Button { 145 | 146 | } label: { 147 | Text("GET") 148 | .fontWeight(.bold) 149 | .foregroundColor(.blue) 150 | .padding(.vertical,8) 151 | .padding(.horizontal, 20) 152 | .background { 153 | Capsule() 154 | .fill(.ultraThinMaterial) 155 | } 156 | 157 | } 158 | 159 | } 160 | .padding([.horizontal, .bottom]) 161 | } 162 | .background { 163 | RoundedRectangle(cornerRadius: 15, style: .continuous) 164 | .fill(Color("BG")) 165 | } 166 | .matchedGeometryEffect(id: item.id, in: animation) 167 | } 168 | 169 | // MARK: - Detail View 170 | @ViewBuilder 171 | func DetailView(item: Today) -> some View { 172 | ScrollView(.vertical, showsIndicators: false) { 173 | VStack { 174 | CardView(item: item) 175 | .scaleEffect(animateView ? 1 : 0.90) 176 | 177 | VStack(spacing: 15) { 178 | // Dummy Text 179 | Text(dummyText) 180 | .multilineTextAlignment(.leading) 181 | .lineSpacing(10) 182 | .padding(.bottom, 20) 183 | 184 | Divider() 185 | 186 | Button { 187 | 188 | } label: { 189 | Label { 190 | Text("Share Story") 191 | } icon: { 192 | Image(systemName: "square.and.arrow.up.fill") 193 | } 194 | .foregroundColor(.primary) 195 | .padding(.vertical, 10) 196 | .padding(.horizontal, 25) 197 | .background { 198 | RoundedRectangle(cornerRadius: 5, style: .continuous) 199 | .fill(.ultraThinMaterial) 200 | } 201 | 202 | } 203 | 204 | } 205 | .padding() 206 | .offset(y: scrollOffset > 0 ? scrollOffset : 0) 207 | .opacity(animateContent ? 1 : 0) 208 | .scaleEffect(animateView ? 1 : 0, anchor: .top) 209 | } 210 | .offset(y: scrollOffset > 0 ? -scrollOffset : 0) 211 | .offset(offset: $scrollOffset) 212 | } 213 | .coordinateSpace(name: "SCROLL") 214 | .overlay(alignment: .topTrailing, content: { 215 | Button { 216 | withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.7, blendDuration: 0.7)) { 217 | animateView = false 218 | animateContent = false 219 | } 220 | 221 | withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.7, blendDuration: 0.7)) { 222 | currentItem = nil 223 | showDetailPage = false 224 | } 225 | } label: { 226 | Image(systemName: "xmark.circle.fill") 227 | .font(.title) 228 | .foregroundColor(.white) 229 | } 230 | .padding() 231 | .padding(.top, safeArea().top) 232 | }) 233 | .onAppear { 234 | withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.7, blendDuration: 0.7)) { 235 | animateView = true 236 | } 237 | 238 | withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.7, blendDuration: 0.7).delay(0.1)) { 239 | animateContent = true 240 | } 241 | } 242 | .transition(.identity) 243 | } 244 | } 245 | 246 | struct Home_Previews: PreviewProvider { 247 | static var previews: some View { 248 | Home() 249 | .preferredColorScheme(.dark) 250 | } 251 | } 252 | 253 | // MARK: - Scale Button Style 254 | struct ScaleButtonStyle: ButtonStyle { 255 | func makeBody(configuration: Configuration) -> some View { 256 | configuration.label 257 | .scaleEffect(configuration.isPressed ? 0.94 : 1) 258 | .animation(.easeInOut, value: configuration.isPressed) 259 | } 260 | } 261 | 262 | // State Area Value 263 | extension View { 264 | func safeArea() -> UIEdgeInsets { 265 | guard let screen = UIApplication.shared 266 | .connectedScenes.first as? UIWindowScene else { 267 | return .zero 268 | } 269 | 270 | guard let safeArea = screen.windows.first?.safeAreaInsets else { 271 | return .zero 272 | } 273 | 274 | return safeArea 275 | } 276 | 277 | // MARK: - Scroll View offset 278 | func offset(offset: Binding) -> some View { 279 | return self 280 | .overlay { 281 | GeometryReader { proxy in 282 | let minY = proxy.frame(in: .named("SCROLL")).minY 283 | 284 | Color.clear 285 | .preference(key: OffsetKey.self, value: minY) 286 | } 287 | .onPreferenceChange(OffsetKey.self) { value in 288 | offset.wrappedValue = value 289 | } 290 | } 291 | } 292 | } 293 | 294 | // MARK: - OffsetKey 295 | struct OffsetKey: PreferenceKey { 296 | static var defaultValue: CGFloat = 0 297 | static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { 298 | value = nextValue() 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftUI Animation Challenge - App Store + Animation 2 | UI: Appstore + animation 3 | 👤 **SheepofG** 4 | - LinkedIn: [@nguyễn-quang](https://www.linkedin.com/in/nguyen-quang-515565188/) 5 | ## Image 6 | ![Screen Shot 2022-04-12 at 15 14 11](https://user-images.githubusercontent.com/78789259/162913655-9e7ace03-c090-45ca-834f-c78129b67d3d.png) 7 | ## Demo 8 | Uploading Screen Recording 2022-04-12 at 15.14.40.mov… 9 | 10 | --------------------------------------------------------------------------------