From f385cd492928b7e2ea61ada5248895121ca79f78 Mon Sep 17 00:00:00 2001 From: Ivan Vorobei Date: Fri, 7 Jun 2019 08:58:01 +0300 Subject: [PATCH] Add SwiftUI + Redux --- .../SwiftUIDemo.xcodeproj/project.pbxproj | 495 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../SwiftUIDemo/AppDelegate.swift | 41 ++ .../AppIcon.appiconset/Contents.json | 98 ++++ .../SwiftUIDemo/Assets.xcassets/Contents.json | 6 + .../user-image.imageset/Contents.json | 22 + .../user-image.imageset/user-image.png | Bin 0 -> 4064 bytes .../user-image.imageset/user-image@2x.png | Bin 0 -> 1444 bytes .../Base.lproj/LaunchScreen.storyboard | 25 + .../SwiftUI + Redux/SwiftUIDemo/Info.plist | 62 +++ .../Preview Assets.xcassets/Contents.json | 6 + .../SwiftUIDemo/SceneDelegate.swift | 24 + .../SwiftUIDemo/flux/actions/Action.swift | 13 + .../flux/actions/UsersAction.swift | 19 + .../SwiftUIDemo/flux/models/User.swift | 20 + .../SwiftUIDemo/flux/reducers/Reducer.swift | 14 + .../flux/reducers/UsersStateReducer.swift | 42 ++ .../SwiftUIDemo/flux/states/AppState.swift | 34 ++ .../SwiftUIDemo/flux/states/FluxState.swift | 11 + .../SwiftUIDemo/flux/states/UsersState.swift | 20 + .../SwiftUIDemo/views/TabbarView.swift | 32 ++ .../SwiftUIDemo/views/map/MapView.swift | 36 ++ .../views/users/UserDetailView.swift | 53 ++ .../views/users/UserEditForm.swift | 88 ++++ .../views/users/UsersListView.swift | 66 +++ .../views/users/component/Badge.swift | 32 ++ .../views/users/rows/UserRow.swift | 36 ++ README.md | 1 + 29 files changed, 1311 insertions(+) create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.pbxproj create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/AppDelegate.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/Contents.json create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/Contents.json create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image.png create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Assets.xcassets/user-image.imageset/user-image@2x.png create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Base.lproj/LaunchScreen.storyboard create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Info.plist create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/SceneDelegate.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/Action.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/actions/UsersAction.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/models/User.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/Reducer.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/reducers/UsersStateReducer.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/AppState.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/FluxState.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/flux/states/UsersState.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/TabbarView.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/map/MapView.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserDetailView.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UserEditForm.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/users/UsersListView.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/users/component/Badge.swift create mode 100755 Examples/SwiftUI + Redux/SwiftUIDemo/views/users/rows/UserRow.swift 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 0000000000000000000000000000000000000000..f78dc24a5768c705592d331cd2cd6efa9e9af596 GIT binary patch literal 4064 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 + + + + + + + + + + + + + + + + + + + + + + + + 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