diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.pbxproj b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.pbxproj new file mode 100755 index 0000000..72acd98 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.pbxproj @@ -0,0 +1,495 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 6905595122A82C0400639314 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6905595022A82C0400639314 /* AppState.swift */; }; + 69250A8B22A97BE300332EF0 /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69250A8A22A97BE300332EF0 /* Badge.swift */; }; + 69516A5D22A8743500E62A5E /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69516A5C22A8743500E62A5E /* Reducer.swift */; }; + 69516A5F22A8745800E62A5E /* FluxState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69516A5E22A8745800E62A5E /* FluxState.swift */; }; + 69516A6122A8747600E62A5E /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69516A6022A8747600E62A5E /* Action.swift */; }; + 69516A6322A874CE00E62A5E /* UsersStateReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69516A6222A874CE00E62A5E /* UsersStateReducer.swift */; }; + 69516A6522A874F900E62A5E /* UsersAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69516A6422A874F900E62A5E /* UsersAction.swift */; }; + 6994C88022A81130006C5F62 /* UserEditForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6994C87F22A81130006C5F62 /* UserEditForm.swift */; }; + 69C1521A22A8CB3600149392 /* TabbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C1521922A8CB3600149392 /* TabbarView.swift */; }; + 69C1522222A8CF4600149392 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C1522122A8CF4600149392 /* MapView.swift */; }; + 69C1522522A8D01300149392 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69C1522422A8D01300149392 /* MapKit.framework */; }; + 69E06C2D22A6FD6B0081D614 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C2C22A6FD6B0081D614 /* AppDelegate.swift */; }; + 69E06C2F22A6FD6B0081D614 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C2E22A6FD6B0081D614 /* SceneDelegate.swift */; }; + 69E06C3122A6FD6B0081D614 /* UsersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C3022A6FD6B0081D614 /* UsersListView.swift */; }; + 69E06C3322A6FD6D0081D614 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69E06C3222A6FD6D0081D614 /* Assets.xcassets */; }; + 69E06C3622A6FD6D0081D614 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69E06C3522A6FD6D0081D614 /* Preview Assets.xcassets */; }; + 69E06C3922A6FD6D0081D614 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69E06C3722A6FD6D0081D614 /* LaunchScreen.storyboard */; }; + 69E06C4422A6FE940081D614 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C4322A6FE940081D614 /* User.swift */; }; + 69E06C4622A6FF3C0081D614 /* UsersState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C4522A6FF3C0081D614 /* UsersState.swift */; }; + 69E06C4922A7016B0081D614 /* UserRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C4822A7016B0081D614 /* UserRow.swift */; }; + 69E06C4C22A706450081D614 /* UserDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E06C4B22A706450081D614 /* UserDetailView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6905595022A82C0400639314 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; + 69250A8A22A97BE300332EF0 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = ""; }; + 69516A5C22A8743500E62A5E /* Reducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reducer.swift; sourceTree = ""; }; + 69516A5E22A8745800E62A5E /* FluxState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FluxState.swift; sourceTree = ""; }; + 69516A6022A8747600E62A5E /* Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; + 69516A6222A874CE00E62A5E /* UsersStateReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersStateReducer.swift; sourceTree = ""; }; + 69516A6422A874F900E62A5E /* UsersAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersAction.swift; sourceTree = ""; }; + 6994C87F22A81130006C5F62 /* UserEditForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEditForm.swift; sourceTree = ""; }; + 69C1521922A8CB3600149392 /* TabbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarView.swift; sourceTree = ""; }; + 69C1522122A8CF4600149392 /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; + 69C1522422A8D01300149392 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + 69E06C2922A6FD6B0081D614 /* SwiftUIDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 69E06C2C22A6FD6B0081D614 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 69E06C2E22A6FD6B0081D614 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 69E06C3022A6FD6B0081D614 /* UsersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersListView.swift; sourceTree = ""; }; + 69E06C3222A6FD6D0081D614 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 69E06C3522A6FD6D0081D614 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 69E06C3822A6FD6D0081D614 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 69E06C3A22A6FD6D0081D614 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 69E06C4322A6FE940081D614 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 69E06C4522A6FF3C0081D614 /* UsersState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersState.swift; sourceTree = ""; }; + 69E06C4822A7016B0081D614 /* UserRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRow.swift; sourceTree = ""; }; + 69E06C4B22A706450081D614 /* UserDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 69E06C2622A6FD6B0081D614 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 69C1522522A8D01300149392 /* MapKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 69250A8922A97BD500332EF0 /* component */ = { + isa = PBXGroup; + children = ( + 69250A8A22A97BE300332EF0 /* Badge.swift */, + ); + path = component; + sourceTree = ""; + }; + 69516A5822A873C900E62A5E /* states */ = { + isa = PBXGroup; + children = ( + 69516A5E22A8745800E62A5E /* FluxState.swift */, + 6905595022A82C0400639314 /* AppState.swift */, + 69E06C4522A6FF3C0081D614 /* UsersState.swift */, + ); + path = states; + sourceTree = ""; + }; + 69516A5922A873D100E62A5E /* actions */ = { + isa = PBXGroup; + children = ( + 69516A6022A8747600E62A5E /* Action.swift */, + 69516A6422A874F900E62A5E /* UsersAction.swift */, + ); + path = actions; + sourceTree = ""; + }; + 69516A5A22A873D700E62A5E /* reducers */ = { + isa = PBXGroup; + children = ( + 69516A5C22A8743500E62A5E /* Reducer.swift */, + 69516A6222A874CE00E62A5E /* UsersStateReducer.swift */, + ); + path = reducers; + sourceTree = ""; + }; + 69C1521F22A8CF2A00149392 /* users */ = { + isa = PBXGroup; + children = ( + 69250A8922A97BD500332EF0 /* component */, + 69E06C4722A7015F0081D614 /* rows */, + 69E06C3022A6FD6B0081D614 /* UsersListView.swift */, + 69E06C4B22A706450081D614 /* UserDetailView.swift */, + 6994C87F22A81130006C5F62 /* UserEditForm.swift */, + ); + path = users; + sourceTree = ""; + }; + 69C1522022A8CF3800149392 /* map */ = { + isa = PBXGroup; + children = ( + 69C1522122A8CF4600149392 /* MapView.swift */, + ); + path = map; + sourceTree = ""; + }; + 69C1522322A8D01300149392 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 69C1522422A8D01300149392 /* MapKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 69E06C2022A6FD6B0081D614 = { + isa = PBXGroup; + children = ( + 69E06C2B22A6FD6B0081D614 /* SwiftUIDemo */, + 69E06C2A22A6FD6B0081D614 /* Products */, + 69C1522322A8D01300149392 /* Frameworks */, + ); + sourceTree = ""; + }; + 69E06C2A22A6FD6B0081D614 /* Products */ = { + isa = PBXGroup; + children = ( + 69E06C2922A6FD6B0081D614 /* SwiftUIDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + 69E06C2B22A6FD6B0081D614 /* SwiftUIDemo */ = { + isa = PBXGroup; + children = ( + 69F83D4822A85D8E00268B3F /* flux */, + 69E06C4A22A7061E0081D614 /* views */, + 69E06C2C22A6FD6B0081D614 /* AppDelegate.swift */, + 69E06C2E22A6FD6B0081D614 /* SceneDelegate.swift */, + 69E06C3222A6FD6D0081D614 /* Assets.xcassets */, + 69E06C3722A6FD6D0081D614 /* LaunchScreen.storyboard */, + 69E06C3A22A6FD6D0081D614 /* Info.plist */, + 69E06C3422A6FD6D0081D614 /* Preview Content */, + ); + path = SwiftUIDemo; + sourceTree = ""; + }; + 69E06C3422A6FD6D0081D614 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 69E06C3522A6FD6D0081D614 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 69E06C4022A6FD730081D614 /* models */ = { + isa = PBXGroup; + children = ( + 69E06C4322A6FE940081D614 /* User.swift */, + ); + path = models; + sourceTree = ""; + }; + 69E06C4722A7015F0081D614 /* rows */ = { + isa = PBXGroup; + children = ( + 69E06C4822A7016B0081D614 /* UserRow.swift */, + ); + path = rows; + sourceTree = ""; + }; + 69E06C4A22A7061E0081D614 /* views */ = { + isa = PBXGroup; + children = ( + 69C1522022A8CF3800149392 /* map */, + 69C1521F22A8CF2A00149392 /* users */, + 69C1521922A8CB3600149392 /* TabbarView.swift */, + ); + path = views; + sourceTree = ""; + }; + 69F83D4822A85D8E00268B3F /* flux */ = { + isa = PBXGroup; + children = ( + 69516A5A22A873D700E62A5E /* reducers */, + 69516A5922A873D100E62A5E /* actions */, + 69516A5822A873C900E62A5E /* states */, + 69E06C4022A6FD730081D614 /* models */, + ); + path = flux; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 69E06C2822A6FD6B0081D614 /* SwiftUIDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 69E06C3D22A6FD6D0081D614 /* Build configuration list for PBXNativeTarget "SwiftUIDemo" */; + buildPhases = ( + 69E06C2522A6FD6B0081D614 /* Sources */, + 69E06C2622A6FD6B0081D614 /* Frameworks */, + 69E06C2722A6FD6B0081D614 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftUIDemo; + productName = SwiftUIDemo; + productReference = 69E06C2922A6FD6B0081D614 /* SwiftUIDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 69E06C2122A6FD6B0081D614 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "Thomas Ricouarf"; + TargetAttributes = { + 69E06C2822A6FD6B0081D614 = { + CreatedOnToolsVersion = 11.0; + }; + }; + }; + buildConfigurationList = 69E06C2422A6FD6B0081D614 /* Build configuration list for PBXProject "SwiftUIDemo" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 69E06C2022A6FD6B0081D614; + productRefGroup = 69E06C2A22A6FD6B0081D614 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 69E06C2822A6FD6B0081D614 /* SwiftUIDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 69E06C2722A6FD6B0081D614 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 69E06C3922A6FD6D0081D614 /* LaunchScreen.storyboard in Resources */, + 69E06C3622A6FD6D0081D614 /* Preview Assets.xcassets in Resources */, + 69E06C3322A6FD6D0081D614 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 69E06C2522A6FD6B0081D614 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 69E06C4622A6FF3C0081D614 /* UsersState.swift in Sources */, + 69516A6522A874F900E62A5E /* UsersAction.swift in Sources */, + 69516A6122A8747600E62A5E /* Action.swift in Sources */, + 69E06C4422A6FE940081D614 /* User.swift in Sources */, + 69516A6322A874CE00E62A5E /* UsersStateReducer.swift in Sources */, + 69E06C2D22A6FD6B0081D614 /* AppDelegate.swift in Sources */, + 69516A5D22A8743500E62A5E /* Reducer.swift in Sources */, + 69E06C2F22A6FD6B0081D614 /* SceneDelegate.swift in Sources */, + 69E06C4C22A706450081D614 /* UserDetailView.swift in Sources */, + 69250A8B22A97BE300332EF0 /* Badge.swift in Sources */, + 69C1522222A8CF4600149392 /* MapView.swift in Sources */, + 69E06C3122A6FD6B0081D614 /* UsersListView.swift in Sources */, + 6905595122A82C0400639314 /* AppState.swift in Sources */, + 6994C88022A81130006C5F62 /* UserEditForm.swift in Sources */, + 69516A5F22A8745800E62A5E /* FluxState.swift in Sources */, + 69C1521A22A8CB3600149392 /* TabbarView.swift in Sources */, + 69E06C4922A7016B0081D614 /* UserRow.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 69E06C3722A6FD6D0081D614 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 69E06C3822A6FD6D0081D614 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 69E06C3B22A6FD6D0081D614 /* 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_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 = 13.0; + 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; + }; + 69E06C3C22A6FD6D0081D614 /* 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_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 = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 69E06C3E22A6FD6D0081D614 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "SwiftUIDemo/Preview\\ Content"; + DEVELOPMENT_TEAM = Z6P74P6T99; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = SwiftUIDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.SwiftUIDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 69E06C3F22A6FD6D0081D614 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "SwiftUIDemo/Preview\\ Content"; + DEVELOPMENT_TEAM = Z6P74P6T99; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = SwiftUIDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.thomasricouard.SwiftUIDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 69E06C2422A6FD6B0081D614 /* Build configuration list for PBXProject "SwiftUIDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 69E06C3B22A6FD6D0081D614 /* Debug */, + 69E06C3C22A6FD6D0081D614 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 69E06C3D22A6FD6D0081D614 /* Build configuration list for PBXNativeTarget "SwiftUIDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 69E06C3E22A6FD6D0081D614 /* Debug */, + 69E06C3F22A6FD6D0081D614 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 69E06C2122A6FD6B0081D614 /* Project object */; +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..e5954d1 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100755 index 0000000..18d9810 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/AppDelegate.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/AppDelegate.swift new file mode 100755 index 0000000..1a0e145 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/AppDelegate.swift @@ -0,0 +1,41 @@ +// +// AppDelegate.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..d8db8d6 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/Contents.json b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/Contents.json new file mode 100755 index 0000000..da4a164 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/Contents.json b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/Contents.json new file mode 100755 index 0000000..7fef6bd --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "user-image.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "user-image@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image.png b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image.png new file mode 100755 index 0000000..f78dc24 Binary files /dev/null and b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image.png differ diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image@2x.png b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image@2x.png new file mode 100755 index 0000000..a674d48 Binary files /dev/null and b/Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image@2x.png differ diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Base.lproj/LaunchScreen.storyboard b/Examples/SwiftUI + Redux/SwiftUIDemo/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 0000000..865e932 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Info.plist b/Examples/SwiftUI + Redux/SwiftUIDemo/Info.plist new file mode 100755 index 0000000..e8bb4c6 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Info.plist @@ -0,0 +1,62 @@ + + + + + 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 + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UILaunchStoryboardName + LaunchScreen + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json b/Examples/SwiftUI + Redux/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100755 index 0000000..da4a164 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/SceneDelegate.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/SceneDelegate.swift new file mode 100755 index 0000000..76089c0 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/SceneDelegate.swift @@ -0,0 +1,24 @@ +// +// SceneDelegate.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import UIKit +import SwiftUI + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + + let window = UIWindow(frame: UIScreen.main.bounds) + window.rootViewController = UIHostingController(rootView: TabbarView().environmentObject(store)) + self.window = window + window.makeKeyAndVisible() + } +} + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/Action.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/Action.swift new file mode 100755 index 0000000..0de6f62 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/Action.swift @@ -0,0 +1,13 @@ +// +// Action.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation + +protocol Action { + +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/UsersAction.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/UsersAction.swift new file mode 100755 index 0000000..88631a8 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/UsersAction.swift @@ -0,0 +1,19 @@ +// +// UsersAction.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation + +enum UserActions: Action { + case addUser + case deleteUser(index: Int) + case move(from: Int, to: Int) + case editUser(id: Int, name: String, username: String) + case testEditFirstUser + case startEditUser + case stopEditUser +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/models/User.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/models/User.swift new file mode 100755 index 0000000..616ee06 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/models/User.swift @@ -0,0 +1,20 @@ +// +// User.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation +import SwiftUI + +struct User: Identifiable { + let id: Int + var name: String + var username: String + let imageName = "person" +} + +let sampleData = [User(id: 0, name: "user 1", username: "@user1"), + User(id: 1, name: "user 2", username: "@user2")] diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/Reducer.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/Reducer.swift new file mode 100755 index 0000000..d89a916 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/Reducer.swift @@ -0,0 +1,14 @@ +// +// Reducer.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation + +protocol Reducer { + associatedtype StateType: FluxState + func reduce(state: StateType, action: Action) -> StateType +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/UsersStateReducer.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/UsersStateReducer.swift new file mode 100755 index 0000000..b2d492e --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/UsersStateReducer.swift @@ -0,0 +1,42 @@ +// +// UsersStateReducer.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation + +struct UserStateReducer: Reducer { + func reduce(state: UsersState, action: Action) -> UsersState { + var state = state + switch action { + case UserActions.addUser: + state.users.append(User(id: state.users.count, + name: "New user \(state.users.count + 1)", + username: "@newuser\(state.users.count + 1)")) + case let UserActions.deleteUser(index): + state.users.remove(at: index) + case let UserActions.move(from, to): + let user = state.users.remove(at: from) + state.users.insert(user, at: to) + case let UserActions.editUser(id, name, username): + var user = state.users[id] + user.name = name + user.username = username + state.users[id] = user + case UserActions.testEditFirstUser: + if !state.users.isEmpty { + state.users[0] = User(id: 0, name: "user1", username: "u\ns\ne\nr\nn\na\nm\ne") + } + case UserActions.startEditUser: + state.isEditingUser = true + case UserActions.stopEditUser: + state.isEditingUser = false + default: + break + } + return state + } +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/AppState.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/AppState.swift new file mode 100755 index 0000000..edbc377 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/AppState.swift @@ -0,0 +1,34 @@ +// +// AppStore.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation +import SwiftUI +import Combine + +final class AppState: BindableObject { + var didChange = PassthroughSubject() + + var usersState: UsersState + + init(usersState: UsersState = UsersState()) { + self.usersState = usersState + } + + func dispatch(action: Action) { + usersState = UserStateReducer().reduce(state: usersState, action: action) + didChange.send(self) + } +} + +let store = AppState() + +#if DEBUG +let sampleStore = AppState(usersState: UsersState(users: sampleData)) +#endif + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/FluxState.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/FluxState.swift new file mode 100755 index 0000000..4c6243a --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/FluxState.swift @@ -0,0 +1,11 @@ +// +// FluxState.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation + +protocol FluxState { } diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/UsersState.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/UsersState.swift new file mode 100755 index 0000000..6f96bd9 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/UsersState.swift @@ -0,0 +1,20 @@ +// +// UsersStore.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import Foundation +import SwiftUI +import Combine + +struct UsersState: FluxState { + var users: [User] + var isEditingUser = false + + init(users: [User] = []) { + self.users = users + } +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/TabbarView.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/TabbarView.swift new file mode 100755 index 0000000..9f0ba72 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/TabbarView.swift @@ -0,0 +1,32 @@ +// +// MainView.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI + +struct TabbarView : View { + @EnvironmentObject var state: AppState + @State var selectedIndex: Int = 0 + + var body: some View { + TabbedView(selection: $selectedIndex) { + UsersListView() + .tabItemLabel(Text("Users")) + MapView() + .tabItemLabel(Text("Map")) + } + } +} + +#if DEBUG +struct MainView_Previews : PreviewProvider { + static var previews: some View { + TabbarView(selectedIndex: 0).environmentObject(sampleStore) + } +} +#endif + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/map/MapView.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/map/MapView.swift new file mode 100755 index 0000000..72a5010 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/map/MapView.swift @@ -0,0 +1,36 @@ + +// +// MapVie.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 05/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI +import UIKit +import MapKit + +struct MapViewRepresentable: UIViewRepresentable { + func makeUIView(context: Context) -> MKMapView { + return MKMapView() + } + + func updateUIView(_ uiView: MKMapView, context: Context) { + + } +} + +struct MapView : View { + var body: some View { + MapViewRepresentable() + } +} + +#if DEBUG +struct MapVie_Previews : PreviewProvider { + static var previews: some View { + MapView() + } +} +#endif diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserDetailView.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserDetailView.swift new file mode 100755 index 0000000..0393fe8 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserDetailView.swift @@ -0,0 +1,53 @@ +// +// UserDetailView.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI +import Combine + +struct UserDetailView : View { + @EnvironmentObject var state: AppState + let userId: Int + + var editModal: Modal { + let user = state.usersState.users[userId] + return Modal(UserEditForm(userId: user.id, saveHandler: { saved in + self.state.dispatch(action: UserActions.stopEditUser) + }).environmentObject(state)) { + self.state.dispatch(action: UserActions.stopEditUser) + } + } + + var body: some View { + let user = state.usersState.users[userId] + return VStack { + Image(systemName: user.imageName) + Text(user.name) + Text(user.username).lineLimit(0) + } + .navigationBarTitle(Text(user.name), displayMode: .inline) + .navigationBarItems(trailing: + Button(action: { + self.state.dispatch(action: UserActions.startEditUser) + }) { + Text("Edit user") + } + .presentation(self.state.usersState.isEditingUser ? self.editModal : nil)) + } +} + +#if DEBUG +struct UserDetailView_Previews : PreviewProvider { + static var previews: some View { + NavigationView { + UserDetailView(userId: 0).environmentObject(sampleStore) + } + } +} +#endif + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserEditForm.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserEditForm.swift new file mode 100755 index 0000000..b8092b3 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserEditForm.swift @@ -0,0 +1,88 @@ + // + // UserEditForm.swift + // SwiftUIDemo + // + // Created by Thomas Ricouard on 05/06/2019. + // Copyright © 2019 Thomas Ricouarf. All rights reserved. + // + + import SwiftUI + + struct UserEditForm : View { + @EnvironmentObject var state: AppState + + let userId: Int + let saveHandler: ((Bool) -> Swift.Void)? + + @State var newUserName = "" + @State var newUserUsername = "" + @State var showSaved = false + @State var showError = false + + var body: some View { + let user = state.usersState.users[userId] + return NavigationView { + VStack(alignment: .leading, spacing: 10) { + Text("User name") + TextField($newUserName, placeholder: Text("New name")) + .textFieldStyle(.roundedBorder) + Divider() + Text("Username") + TextField($newUserUsername, placeholder: Text("New username")) + .textFieldStyle(.roundedBorder) + }.padding(16) + Button(action: save) { + Text("Save") + .padding(8) + .foregroundColor(.white) + .background(Color.green) + .cornerRadius(8) + } + .navigationBarItems(trailing: Button(action: close) { + Text("Close") + }) + .navigationBarTitle(Text("Edit \(user.name)"), displayMode: .inline) + + Badge(text: "Saved successfully", color: .green, show: $showSaved) + Badge(text: "Missing username or name", color: .red, show: $showError) + } + } + + func save() { + guard !newUserName.isEmpty && !newUserUsername.isEmpty else { + withAnimation{ + showError = true + } + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.showError = false + } + return + } + + withAnimation { + showSaved = true + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.showSaved = false + } + + state.dispatch(action: UserActions.editUser(id: userId, name: newUserName, username: newUserUsername)) + saveHandler?(true) + } + + func close() { + saveHandler?(false) + } + } + + #if DEBUG + struct UserEditForm_Previews : PreviewProvider { + static var previews: some View { + UserEditForm(userId: 0, saveHandler: nil).environmentObject(sampleStore) + } + } + #endif + + + diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UsersListView.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UsersListView.swift new file mode 100755 index 0000000..f13f810 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UsersListView.swift @@ -0,0 +1,66 @@ +// +// ContentView.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI + +struct UsersListView : View { + @EnvironmentObject var state: AppState + + var body: some View { + NavigationView { + List { + Section { + Button(action: addUser) { + Text("Add user") + } + Button(action: targetUpdate) { + Text("Update first") + } + } + Section { + ForEach(state.usersState.users) {user in + NavigationButton(destination: UserDetailView(userId: user.id)) { + UserRow(user: user) + } + } + .onDelete(perform: delete) + .onMove(perform: move) + } + } + .listStyle(.grouped) + .navigationBarTitle(Text("Users (\(state.usersState.users.count))")) + .navigationBarItems(trailing: EditButton()) + } + + } + + func addUser() { + state.dispatch(action: UserActions.addUser) + + } + + func targetUpdate() { + state.dispatch(action: UserActions.testEditFirstUser) + } + + func delete(at offset: IndexSet) { + state.dispatch(action: UserActions.deleteUser(index: offset.first!)) + } + + func move(from: IndexSet, to: Int) { + state.dispatch(action: UserActions.move(from: from.first!, to: to)) + } +} + +#if DEBUG +struct ContentView_Previews : PreviewProvider { + static var previews: some View { + UsersListView().environmentObject(sampleStore) + } +} +#endif diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/component/Badge.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/component/Badge.swift new file mode 100755 index 0000000..f900edf --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/component/Badge.swift @@ -0,0 +1,32 @@ +// +// GreenBadge.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 06/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI + +struct Badge : View { + let text: String + let color: Color + @Binding var show: Bool + + var animation: Animation { + Animation + .spring(initialVelocity: 5) + .speed(2) + } + + var body: some View { + Text(text) + .color(.white) + .padding() + .background(color) + .cornerRadius(8) + .scaleEffect(show ? 1: 0.5) + .opacity(show ? 1 : 0) + .animation(animation) + } +} diff --git a/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/rows/UserRow.swift b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/rows/UserRow.swift new file mode 100755 index 0000000..ec1af61 --- /dev/null +++ b/Examples/SwiftUI + Redux/SwiftUIDemo/views/users/rows/UserRow.swift @@ -0,0 +1,36 @@ +// +// UserRw.swift +// SwiftUIDemo +// +// Created by Thomas Ricouard on 04/06/2019. +// Copyright © 2019 Thomas Ricouarf. All rights reserved. +// + +import SwiftUI + +struct UserRow : View { + let user: User + + var body: some View { + VStack { + HStack { + Image(systemName: user.imageName) + + VStack { + Text(user.name) + Text(user.username) + .color(.secondary) + .lineLimit(0) + } + } + } + } +} + +#if DEBUG +struct UserRw_Previews : PreviewProvider { + static var previews: some View { + UserRow(user: sampleData[0]) + } +} +#endif diff --git a/README.md b/README.md index 9ff36c6..5228d9b 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Also include: - Movie - InstaFake - TempusRomanumII +- SwiftUI + Redux ## Projects