From af21306b10769b4440957c514796793533189bc8 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 22 Feb 2021 19:01:29 -0500 Subject: [PATCH] 136 --- .../Animations.xcodeproj/project.pbxproj | 610 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../Animations/Animations/AnimationsApp.swift | 11 + .../Animations/Animations/AnimationsTCA.swift | 228 +++++++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 +++ .../Animations/Assets.xcassets/Contents.json | 6 + .../Animations/Animations/ContentView.swift | 97 +++ .../Animations/Animations/Info.plist | 50 ++ .../Preview Assets.xcassets/Contents.json | 6 + .../AnimationsTests/AnimationsTests.swift | 33 + .../Animations/AnimationsTests/Info.plist | 22 + .../AnimationsUITests/AnimationsUITests.swift | 42 ++ .../Animations/AnimationsUITests/Info.plist | 22 + 0136-swiftui-animation-pt2/README.md | 5 + README.md | 1 + 17 files changed, 1257 insertions(+) create mode 100644 0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.pbxproj create mode 100644 0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/AnimationsApp.swift create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/AnimationsTCA.swift create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/Contents.json create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/ContentView.swift create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/Info.plist create mode 100644 0136-swiftui-animation-pt2/Animations/Animations/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 0136-swiftui-animation-pt2/Animations/AnimationsTests/AnimationsTests.swift create mode 100644 0136-swiftui-animation-pt2/Animations/AnimationsTests/Info.plist create mode 100644 0136-swiftui-animation-pt2/Animations/AnimationsUITests/AnimationsUITests.swift create mode 100644 0136-swiftui-animation-pt2/Animations/AnimationsUITests/Info.plist create mode 100644 0136-swiftui-animation-pt2/README.md diff --git a/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.pbxproj b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.pbxproj new file mode 100644 index 00000000..b1943a9f --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.pbxproj @@ -0,0 +1,610 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 2A89E3BF25D2F8BE00A1EF57 /* AnimationsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A89E3BE25D2F8BE00A1EF57 /* AnimationsApp.swift */; }; + 2A89E3C125D2F8BE00A1EF57 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A89E3C025D2F8BE00A1EF57 /* ContentView.swift */; }; + 2A89E3C325D2F8BE00A1EF57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A89E3C225D2F8BE00A1EF57 /* Assets.xcassets */; }; + 2A89E3C625D2F8BE00A1EF57 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A89E3C525D2F8BE00A1EF57 /* Preview Assets.xcassets */; }; + 2A89E3D125D2F8BE00A1EF57 /* AnimationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A89E3D025D2F8BE00A1EF57 /* AnimationsTests.swift */; }; + 2A89E3DC25D2F8BF00A1EF57 /* AnimationsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A89E3DB25D2F8BF00A1EF57 /* AnimationsUITests.swift */; }; + 4B23A43025D3139E005194BD /* AnimationsTCA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B23A42F25D3139E005194BD /* AnimationsTCA.swift */; }; + 4B23A43625D313FB005194BD /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = 4B23A43525D313FB005194BD /* ComposableArchitecture */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 2A89E3CD25D2F8BE00A1EF57 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2A89E3B325D2F8BE00A1EF57 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2A89E3BA25D2F8BE00A1EF57; + remoteInfo = Animations; + }; + 2A89E3D825D2F8BF00A1EF57 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2A89E3B325D2F8BE00A1EF57 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2A89E3BA25D2F8BE00A1EF57; + remoteInfo = Animations; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 2A89E3BB25D2F8BE00A1EF57 /* Animations.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Animations.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 2A89E3BE25D2F8BE00A1EF57 /* AnimationsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationsApp.swift; sourceTree = ""; }; + 2A89E3C025D2F8BE00A1EF57 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 2A89E3C225D2F8BE00A1EF57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 2A89E3C525D2F8BE00A1EF57 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 2A89E3C725D2F8BE00A1EF57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2A89E3CC25D2F8BE00A1EF57 /* AnimationsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnimationsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 2A89E3D025D2F8BE00A1EF57 /* AnimationsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationsTests.swift; sourceTree = ""; }; + 2A89E3D225D2F8BE00A1EF57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2A89E3D725D2F8BF00A1EF57 /* AnimationsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnimationsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 2A89E3DB25D2F8BF00A1EF57 /* AnimationsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationsUITests.swift; sourceTree = ""; }; + 2A89E3DD25D2F8BF00A1EF57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4B23A42F25D3139E005194BD /* AnimationsTCA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationsTCA.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2A89E3B825D2F8BE00A1EF57 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4B23A43625D313FB005194BD /* ComposableArchitecture in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3C925D2F8BE00A1EF57 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3D425D2F8BF00A1EF57 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2A89E3B225D2F8BE00A1EF57 = { + isa = PBXGroup; + children = ( + 2A89E3BD25D2F8BE00A1EF57 /* Animations */, + 2A89E3CF25D2F8BE00A1EF57 /* AnimationsTests */, + 2A89E3DA25D2F8BF00A1EF57 /* AnimationsUITests */, + 2A89E3BC25D2F8BE00A1EF57 /* Products */, + ); + sourceTree = ""; + }; + 2A89E3BC25D2F8BE00A1EF57 /* Products */ = { + isa = PBXGroup; + children = ( + 2A89E3BB25D2F8BE00A1EF57 /* Animations.app */, + 2A89E3CC25D2F8BE00A1EF57 /* AnimationsTests.xctest */, + 2A89E3D725D2F8BF00A1EF57 /* AnimationsUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 2A89E3BD25D2F8BE00A1EF57 /* Animations */ = { + isa = PBXGroup; + children = ( + 2A89E3BE25D2F8BE00A1EF57 /* AnimationsApp.swift */, + 2A89E3C025D2F8BE00A1EF57 /* ContentView.swift */, + 4B23A42F25D3139E005194BD /* AnimationsTCA.swift */, + 2A89E3C225D2F8BE00A1EF57 /* Assets.xcassets */, + 2A89E3C725D2F8BE00A1EF57 /* Info.plist */, + 2A89E3C425D2F8BE00A1EF57 /* Preview Content */, + ); + path = Animations; + sourceTree = ""; + }; + 2A89E3C425D2F8BE00A1EF57 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 2A89E3C525D2F8BE00A1EF57 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 2A89E3CF25D2F8BE00A1EF57 /* AnimationsTests */ = { + isa = PBXGroup; + children = ( + 2A89E3D025D2F8BE00A1EF57 /* AnimationsTests.swift */, + 2A89E3D225D2F8BE00A1EF57 /* Info.plist */, + ); + path = AnimationsTests; + sourceTree = ""; + }; + 2A89E3DA25D2F8BF00A1EF57 /* AnimationsUITests */ = { + isa = PBXGroup; + children = ( + 2A89E3DB25D2F8BF00A1EF57 /* AnimationsUITests.swift */, + 2A89E3DD25D2F8BF00A1EF57 /* Info.plist */, + ); + path = AnimationsUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2A89E3BA25D2F8BE00A1EF57 /* Animations */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2A89E3E025D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "Animations" */; + buildPhases = ( + 2A89E3B725D2F8BE00A1EF57 /* Sources */, + 2A89E3B825D2F8BE00A1EF57 /* Frameworks */, + 2A89E3B925D2F8BE00A1EF57 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Animations; + packageProductDependencies = ( + 4B23A43525D313FB005194BD /* ComposableArchitecture */, + ); + productName = Animations; + productReference = 2A89E3BB25D2F8BE00A1EF57 /* Animations.app */; + productType = "com.apple.product-type.application"; + }; + 2A89E3CB25D2F8BE00A1EF57 /* AnimationsTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2A89E3E325D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "AnimationsTests" */; + buildPhases = ( + 2A89E3C825D2F8BE00A1EF57 /* Sources */, + 2A89E3C925D2F8BE00A1EF57 /* Frameworks */, + 2A89E3CA25D2F8BE00A1EF57 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2A89E3CE25D2F8BE00A1EF57 /* PBXTargetDependency */, + ); + name = AnimationsTests; + productName = AnimationsTests; + productReference = 2A89E3CC25D2F8BE00A1EF57 /* AnimationsTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 2A89E3D625D2F8BF00A1EF57 /* AnimationsUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2A89E3E625D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "AnimationsUITests" */; + buildPhases = ( + 2A89E3D325D2F8BF00A1EF57 /* Sources */, + 2A89E3D425D2F8BF00A1EF57 /* Frameworks */, + 2A89E3D525D2F8BF00A1EF57 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2A89E3D925D2F8BF00A1EF57 /* PBXTargetDependency */, + ); + name = AnimationsUITests; + productName = AnimationsUITests; + productReference = 2A89E3D725D2F8BF00A1EF57 /* AnimationsUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2A89E3B325D2F8BE00A1EF57 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1240; + LastUpgradeCheck = 1240; + TargetAttributes = { + 2A89E3BA25D2F8BE00A1EF57 = { + CreatedOnToolsVersion = 12.4; + }; + 2A89E3CB25D2F8BE00A1EF57 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = 2A89E3BA25D2F8BE00A1EF57; + }; + 2A89E3D625D2F8BF00A1EF57 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = 2A89E3BA25D2F8BE00A1EF57; + }; + }; + }; + buildConfigurationList = 2A89E3B625D2F8BE00A1EF57 /* Build configuration list for PBXProject "Animations" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 2A89E3B225D2F8BE00A1EF57; + packageReferences = ( + 4B23A43425D313FB005194BD /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, + ); + productRefGroup = 2A89E3BC25D2F8BE00A1EF57 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2A89E3BA25D2F8BE00A1EF57 /* Animations */, + 2A89E3CB25D2F8BE00A1EF57 /* AnimationsTests */, + 2A89E3D625D2F8BF00A1EF57 /* AnimationsUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2A89E3B925D2F8BE00A1EF57 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2A89E3C625D2F8BE00A1EF57 /* Preview Assets.xcassets in Resources */, + 2A89E3C325D2F8BE00A1EF57 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3CA25D2F8BE00A1EF57 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3D525D2F8BF00A1EF57 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2A89E3B725D2F8BE00A1EF57 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4B23A43025D3139E005194BD /* AnimationsTCA.swift in Sources */, + 2A89E3C125D2F8BE00A1EF57 /* ContentView.swift in Sources */, + 2A89E3BF25D2F8BE00A1EF57 /* AnimationsApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3C825D2F8BE00A1EF57 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2A89E3D125D2F8BE00A1EF57 /* AnimationsTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A89E3D325D2F8BF00A1EF57 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2A89E3DC25D2F8BF00A1EF57 /* AnimationsUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 2A89E3CE25D2F8BE00A1EF57 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2A89E3BA25D2F8BE00A1EF57 /* Animations */; + targetProxy = 2A89E3CD25D2F8BE00A1EF57 /* PBXContainerItemProxy */; + }; + 2A89E3D925D2F8BF00A1EF57 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2A89E3BA25D2F8BE00A1EF57 /* Animations */; + targetProxy = 2A89E3D825D2F8BF00A1EF57 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 2A89E3DE25D2F8BF00A1EF57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 2A89E3DF25D2F8BF00A1EF57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2A89E3E125D2F8BF00A1EF57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"Animations/Preview Content\""; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = Animations/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.Animations; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2A89E3E225D2F8BF00A1EF57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"Animations/Preview Content\""; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = Animations/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.Animations; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 2A89E3E425D2F8BF00A1EF57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = AnimationsTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.AnimationsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Animations.app/Animations"; + }; + name = Debug; + }; + 2A89E3E525D2F8BF00A1EF57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = AnimationsTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.AnimationsTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Animations.app/Animations"; + }; + name = Release; + }; + 2A89E3E725D2F8BF00A1EF57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = AnimationsUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.AnimationsUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Animations; + }; + name = Debug; + }; + 2A89E3E825D2F8BF00A1EF57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = AnimationsUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.AnimationsUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Animations; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2A89E3B625D2F8BE00A1EF57 /* Build configuration list for PBXProject "Animations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2A89E3DE25D2F8BF00A1EF57 /* Debug */, + 2A89E3DF25D2F8BF00A1EF57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2A89E3E025D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "Animations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2A89E3E125D2F8BF00A1EF57 /* Debug */, + 2A89E3E225D2F8BF00A1EF57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2A89E3E325D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "AnimationsTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2A89E3E425D2F8BF00A1EF57 /* Debug */, + 2A89E3E525D2F8BF00A1EF57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2A89E3E625D2F8BF00A1EF57 /* Build configuration list for PBXNativeTarget "AnimationsUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2A89E3E725D2F8BF00A1EF57 /* Debug */, + 2A89E3E825D2F8BF00A1EF57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 4B23A43425D313FB005194BD /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.14.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 4B23A43525D313FB005194BD /* ComposableArchitecture */ = { + isa = XCSwiftPackageProductDependency; + package = 4B23A43425D313FB005194BD /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; + productName = ComposableArchitecture; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 2A89E3B325D2F8BE00A1EF57 /* Project object */; +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/0136-swiftui-animation-pt2/Animations/Animations/AnimationsApp.swift b/0136-swiftui-animation-pt2/Animations/Animations/AnimationsApp.swift new file mode 100644 index 00000000..a649d861 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/AnimationsApp.swift @@ -0,0 +1,11 @@ +import SwiftUI + +@main +struct AnimationsApp: App { + var body: some Scene { + WindowGroup { +// ContentView() + TCAContentView(store: .init(initialState: .init(), reducer: appReducer, environment: .init())) + } + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/AnimationsTCA.swift b/0136-swiftui-animation-pt2/Animations/Animations/AnimationsTCA.swift new file mode 100644 index 00000000..70d5f2cb --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/AnimationsTCA.swift @@ -0,0 +1,228 @@ +import ComposableArchitecture +import SwiftUI + +struct AppState: Equatable { + var circleCenter = CGPoint.zero + var circleColor = Color.black + var isCircleScaled = false +} + +enum AppAction { + case cycleColorsButtonTapped + case dragGesture(CGPoint) + case resetButtonTapped + case setCircleColor(Color) + case toggleScale(isOn: Bool) +} + +struct AppEnvironment {} + +import Combine + +extension Scheduler { + func animation(_ animation: Animation? = .default) -> AnySchedulerOf { + .init( + minimumTolerance: { self.minimumTolerance }, + now: { self.now }, + scheduleImmediately: { options, action in + self.schedule(options: options) { + withAnimation(animation, action) + } + }, + delayed: { after, tolerance, options, action in + self.schedule(after: after, tolerance: tolerance, options: options) { + withAnimation(animation, action) + } + }, + interval: { after, interval, tolerance, options, action in + self.schedule(after: after, interval: interval, tolerance: tolerance, options: options) { + withAnimation(animation, action) + } + } + ) + } +} + +//let mainQueue = AnyScheduler( +// minimumTolerance: { DispatchQueue.main.minimumTolerance }, +// now: { DispatchQueue.main.now }, +// scheduleImmediately: DispatchQueue.main.schedule, +// delayed: { duration, tolerance, options, action in +// DispatchQueue.main.schedule(after: duration, tolerance: tolerance, options: options) { +// withAnimation { +// action() +// } +// } +// }, +// interval: DispatchQueue.main.schedule +//) + +let appReducer = Reducer { + state, action, environment in + switch action { + case .cycleColorsButtonTapped: + state.circleColor = .red + return Effect.concatenate( + // withAnimation: (() -> R) -> R + [Color.blue, .green, .purple, .black].enumerated().map { index, color in + Effect(value: withAnimation { .setCircleColor(color) }) + .delay(for: .seconds(1), scheduler: DispatchQueue.main.animation(index.isMultiple(of: 2) ? nil : .linear)) + .eraseToEffect() + } +// Effect(value: AppAction.setCircleColor(.blue)) +// .delay(for: .seconds(1), scheduler: DispatchQueue.main) +// .eraseToEffect(), +// Effect(value: AppAction.setCircleColor(.green)) +// .delay(for: .seconds(1), scheduler: DispatchQueue.main) +// .eraseToEffect(), +// Effect(value: AppAction.setCircleColor(.purple)) +// .delay(for: .seconds(1), scheduler: DispatchQueue.main) +// .eraseToEffect(), +// Effect(value: AppAction.setCircleColor(.black)) +// .delay(for: .seconds(1), scheduler: DispatchQueue.main) +// .eraseToEffect() + ) + + case let .dragGesture(location): + state.circleCenter = location + return .none + + case .resetButtonTapped: + state = AppState() + return .none + + case let .setCircleColor(color): + state.circleColor = color + return .none + + case .toggleScale(isOn: let isOn): + state.isCircleScaled = isOn + return .none + } +} + +extension ViewStore { + func send(_ action: Action, animation: Animation) { + withAnimation(animation) { + self.send(action) + } + } +} + +struct TCAContentView: View { + let store: Store +// @State var circleCenter = CGPoint.zero +// @State var circleColor = Color.black +// @State var isCircleScaled = false +// @State var isResetting = false + + var body: some View { + WithViewStore(self.store) { viewStore in + VStack { + Circle() + .fill(viewStore.circleColor) + // .animation(.linear) + .overlay(Text("Hi")) + .frame(width: 50, height: 50) + .scaleEffect(viewStore.isCircleScaled ? 2 : 1) + // .animation(nil, value: self.isCircleScaled) + // .animation(.disabled) + .offset(x: viewStore.circleCenter.x - 25, y: viewStore.circleCenter.y - 25) +// .animation(.spring(response: 0.3, dampingFraction: 0.1)) + .gesture( + DragGesture(minimumDistance: 0).onChanged { value in +// withAnimation(.spring(response: 0.3, dampingFraction: 0.1)) { +//// viewStore.circleCenter = value.location +// viewStore.send(.dragGesture(value.location)) +// } + viewStore.send(.dragGesture(value.location), animation: .spring(response: 0.3, dampingFraction: 0.1)) + } + ) + .foregroundColor(viewStore.isCircleScaled ? .red : nil) + // if self.isCircleScaled { + // circle.foregroundColor(.red) + // } else { + // circle + // } + + Toggle( + "Scale", + isOn: viewStore.binding( + get: \.isCircleScaled, + send: AppAction.toggleScale(isOn:) + ) + .animation(.spring(response: 0.3, dampingFraction: 0.1)) +// self.$isCircleScaled.animation(.spring(response: 0.3, dampingFraction: 0.1)) + + // Binding( + // get: { self.isCircleScaled }, + // set: { isOn in + // withAnimation(.spring(response: 0.3, dampingFraction: 0.1)) { + // self.isCircleScaled = isOn + // } + // } + // ) + + ) + + Button("Cycle colors") { + withAnimation(.linear) { + viewStore.send(.cycleColorsButtonTapped) + } +// [Color.red, .blue, .green, .purple, .black] +// .enumerated() +// .forEach { offset, color in +// DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(offset)) { +// withAnimation(.linear) { +// self.circleColor = color +// } +// +// // withAnimation: (() -> R) -> R +// // Async = ((A) -> Void) -> Void +// // ((A) -> R) -> R +// } +// } + // DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + // self.circleColor = .blue + // } + // DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + // self.circleColor = .green + // } + // DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + // self.circleColor = .purple + // } + // DispatchQueue.main.asyncAfter(deadline: .now() + 4) { + // self.circleColor = .black + // } + } + + Button("Reset") { +// withAnimation { + viewStore.send(.resetButtonTapped, animation: .linear) +// } + // self.isResetting = true +// withAnimation { +// self.circleCenter = .zero +// self.circleColor = .black +// } +// self.isCircleScaled = false + // DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) { + // self.isResetting = false + // } + } + } + } + } +} + +struct TCAContentView_Previews: PreviewProvider { + static var previews: some View { + TCAContentView( + store: Store( + initialState: AppState(), + reducer: appReducer, + environment: AppEnvironment() + ) + ) + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AccentColor.colorset/Contents.json b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AppIcon.appiconset/Contents.json b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/Contents.json b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/ContentView.swift b/0136-swiftui-animation-pt2/Animations/Animations/ContentView.swift new file mode 100644 index 00000000..e25c4054 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/ContentView.swift @@ -0,0 +1,97 @@ +import SwiftUI + +struct ContentView: View { + @State var circleCenter = CGPoint.zero + @State var circleColor = Color.black + @State var isCircleScaled = false + @State var isResetting = false + + var body: some View { + VStack { + Circle() + .fill(self.circleColor) +// .animation(.linear) + .overlay(Text("Hi")) + .frame(width: 50, height: 50) + .scaleEffect(self.isCircleScaled ? 2 : 1) +// .animation(nil, value: self.isCircleScaled) +// .animation(.disabled) + .offset(x: self.circleCenter.x - 25, y: self.circleCenter.y - 25) +// .animation(self.isResetting ? nil : .spring(response: 0.3, dampingFraction: 0.1)) + .gesture( + DragGesture(minimumDistance: 0).onChanged { value in + withAnimation(.spring(response: 0.3, dampingFraction: 0.1)) { + self.circleCenter = value.location + } + } + ) + .foregroundColor(self.isCircleScaled ? .red : nil) +// if self.isCircleScaled { +// circle.foregroundColor(.red) +// } else { +// circle +// } + + Toggle( + "Scale", + isOn: self.$isCircleScaled.animation(.spring(response: 0.3, dampingFraction: 0.1)) + +// Binding( +// get: { self.isCircleScaled }, +// set: { isOn in +// withAnimation(.spring(response: 0.3, dampingFraction: 0.1)) { +// self.isCircleScaled = isOn +// } +// } +// ) + + ) + + Button("Cycle colors") { + [Color.red, .blue, .green, .purple, .black] + .enumerated() + .forEach { offset, color in + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(offset)) { + withAnimation(.linear) { + self.circleColor = color + } + + // withAnimation: (() -> R) -> R + // Async = ((A) -> Void) -> Void + // ((A) -> R) -> R + } + } +// DispatchQueue.main.asyncAfter(deadline: .now() + 1) { +// self.circleColor = .blue +// } +// DispatchQueue.main.asyncAfter(deadline: .now() + 2) { +// self.circleColor = .green +// } +// DispatchQueue.main.asyncAfter(deadline: .now() + 3) { +// self.circleColor = .purple +// } +// DispatchQueue.main.asyncAfter(deadline: .now() + 4) { +// self.circleColor = .black +// } + } + + Button("Reset") { +// self.isResetting = true + withAnimation { + self.circleCenter = .zero + self.circleColor = .black + } + self.isCircleScaled = false +// DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) { +// self.isResetting = false +// } + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/0136-swiftui-animation-pt2/Animations/Animations/Info.plist b/0136-swiftui-animation-pt2/Animations/Animations/Info.plist new file mode 100644 index 00000000..efc211a0 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UIApplicationSupportsIndirectInputEvents + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/0136-swiftui-animation-pt2/Animations/Animations/Preview Content/Preview Assets.xcassets/Contents.json b/0136-swiftui-animation-pt2/Animations/Animations/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/Animations/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/0136-swiftui-animation-pt2/Animations/AnimationsTests/AnimationsTests.swift b/0136-swiftui-animation-pt2/Animations/AnimationsTests/AnimationsTests.swift new file mode 100644 index 00000000..60c4557e --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/AnimationsTests/AnimationsTests.swift @@ -0,0 +1,33 @@ +// +// AnimationsTests.swift +// AnimationsTests +// +// Created by Point-Free on 2/9/21. +// + +import XCTest +@testable import Animations + +class AnimationsTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/0136-swiftui-animation-pt2/Animations/AnimationsTests/Info.plist b/0136-swiftui-animation-pt2/Animations/AnimationsTests/Info.plist new file mode 100644 index 00000000..64d65ca4 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/AnimationsTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/0136-swiftui-animation-pt2/Animations/AnimationsUITests/AnimationsUITests.swift b/0136-swiftui-animation-pt2/Animations/AnimationsUITests/AnimationsUITests.swift new file mode 100644 index 00000000..d8144177 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/AnimationsUITests/AnimationsUITests.swift @@ -0,0 +1,42 @@ +// +// AnimationsUITests.swift +// AnimationsUITests +// +// Created by Point-Free on 2/9/21. +// + +import XCTest + +class AnimationsUITests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +} diff --git a/0136-swiftui-animation-pt2/Animations/AnimationsUITests/Info.plist b/0136-swiftui-animation-pt2/Animations/AnimationsUITests/Info.plist new file mode 100644 index 00000000..64d65ca4 --- /dev/null +++ b/0136-swiftui-animation-pt2/Animations/AnimationsUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/0136-swiftui-animation-pt2/README.md b/0136-swiftui-animation-pt2/README.md new file mode 100644 index 00000000..9c1cf2f2 --- /dev/null +++ b/0136-swiftui-animation-pt2/README.md @@ -0,0 +1,5 @@ +## [Point-Free](https://www.pointfree.co) + +> #### This directory contains code from Point-Free Episode: [SwiftUI Animation: Composable Architecture](https://www.pointfree.co/episodes/ep136-swiftui-animation-composable-architecture) +> +> The Composable Architecture mostly “just works” with SwiftUI animations out of the box, except for one key situation: animations driven by asynchronous effects. To fix this we are led to a really surprising transformation of Combine schedulers. diff --git a/README.md b/README.md index e3166797..3ed2d840 100644 --- a/README.md +++ b/README.md @@ -137,3 +137,4 @@ This repository is the home of code written on episodes of [Point-Free](https:// 1. [Concise Forms: Bye Bye Boilerplate](0133-concise-forms-pt3) 1. [Concise Forms: The Point](0134-concise-forms-pt4) 1. [SwiftUI Animation: The Basics](0135-swiftui-animation-pt1) +1. [SwiftUI Animation: Composable Architecture](0136-swiftui-animation-pt2)