diff --git a/.travis.yml b/.travis.yml index b6c4c7a..6124697 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,11 @@ env: - LANG=en_US.UTF-8 - APP_NAME="SwiftFlowGitHubBrowser" -osx_image: xcode9 +osx_image: xcode10.1 matrix: include: - - env: SDK="iphonesimulator" DESTINATION="OS=11.0,name=iPhone 8" + - env: SDK="iphonesimulator" DESTINATION="OS=12.1,name=iPhone 8" before_install: - carthage update --no-use-binaries --platform iOS diff --git a/Cartfile b/Cartfile index bf15ee4..dd112b3 100644 --- a/Cartfile +++ b/Cartfile @@ -1,7 +1,9 @@ -github "nerdishbynature/octokit.swift" ~> 0.7.0 -github "Quick/Quick" -github "Quick/Nimble" -github "soffes/SSKeychain" +github "nerdishbynature/octokit.swift" +github "nerdishbynature/RequestKit" "2.3.0" +github "Quick/Quick" "master" +github "Quick/Nimble" "master" +github "soffes/SSKeychain" "master" github "Ben-G/ListKit" -github "ReSwift/ReSwift" ~> 4.0.0 -github "ReSwift/ReSwiftRouter" ~> 0.6.0 +github "ReSwift/ReSwift" "master" +github "ReSwift/ReSwiftRouter" "master" +github "ReSwift/ReSwift-Thunk" "1.1.0" diff --git a/Cartfile.resolved b/Cartfile.resolved index a081f54..458d534 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,8 +1,9 @@ github "Ben-G/ListKit" "2.0.0" -github "Quick/Nimble" "v7.0.2" -github "Quick/Quick" "v1.2.0" -github "ReSwift/ReSwift" "4.0.0" -github "ReSwift/ReSwiftRouter" "0.6.0" -github "nerdishbynature/RequestKit" "2.0.2" -github "nerdishbynature/octokit.swift" "0.7.4" -github "soffes/SSKeychain" "v1.5.3" +github "Quick/Nimble" "d7a8451738e22e76f0465d72b9f3c054df16a56b" +github "Quick/Quick" "5ba1cef76f4dbd24a2ce5a804571667ebfef71a3" +github "ReSwift/ReSwift" "5b7a5c6cd05fa2b7d3f68ef7765acb2ba696d83c" +github "ReSwift/ReSwift-Thunk" "1.1.0" +github "ReSwift/ReSwiftRouter" "17773950b0d1031e185fe6c15cda705fe2b5c204" +github "nerdishbynature/RequestKit" "2.3.0" +github "nerdishbynature/octokit.swift" "0.9.0" +github "soffes/SSKeychain" "d3d64f8c5fa14bf2adb2d51a18ee8b6639232ca5" diff --git a/README.md b/README.md index c778dfe..0b76897 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +![Swift 4.2](https://img.shields.io/badge/Swift-4.2-blue.svg?style=flat) +![License](https://img.shields.io/github/license/ReSwift/GitHubBrowserExample.svg?style=flat) + +---- + Work-in-Progress Real World Example for Swift Flow. This project is currently driving some API changes, so it is using newer APIs than provided by the latest Swift Flow releases. @@ -31,4 +36,4 @@ Open `Credentials.swift` and enter the **Client ID** and the **Client Secret** o // Insert GitHub Token and Secret Here let gitHubClientId = "" let gitHubClientSecret = "" -``` \ No newline at end of file +``` diff --git a/SwiftFlowGitHubBrowser.xcodeproj/project.pbxproj b/SwiftFlowGitHubBrowser.xcodeproj/project.pbxproj index 47c3f73..027b7ac 100644 --- a/SwiftFlowGitHubBrowser.xcodeproj/project.pbxproj +++ b/SwiftFlowGitHubBrowser.xcodeproj/project.pbxproj @@ -45,6 +45,8 @@ 62EF0AB61C700D4900D13711 /* GitHubAuthSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EF0AB51C700D4900D13711 /* GitHubAuthSpec.swift */; }; 62EF0ABA1C700D9D00D13711 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62EF0AA81C700D1F00D13711 /* Nimble.framework */; }; 62EF0ABB1C700DA200D13711 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62EF0A8D1C700D1200D13711 /* Quick.framework */; }; + 66C463FC22270A970006963A /* ReSwiftThunk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66C463F922270A7C0006963A /* ReSwiftThunk.framework */; }; + 66C463FD22270A970006963A /* ReSwiftThunk.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66C463F922270A7C0006963A /* ReSwiftThunk.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7A7A57191C91D78C00670D38 /* ListKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 62C935581C8CD6B400887A23 /* ListKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ @@ -490,6 +492,27 @@ remoteGlobalIDString = 1F5DF15E1BDCA0CE00C3A531; remoteInfo = "Nimble-tvOSTests"; }; + 66C463F822270A7C0006963A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 65A3D6D5218B89A60075CB92; + remoteInfo = "ReSwift-Thunk"; + }; + 66C463FA22270A7C0006963A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 65A3D6DE218B89A60075CB92; + remoteInfo = "ReSwift-Thunk-Tests"; + }; + 66C463FE22270A970006963A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 65A3D6D4218B89A60075CB92; + remoteInfo = "ReSwift-Thunk"; + }; 7A7A571A1C91D78C00670D38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 62C9354C1C8CD6B300887A23 /* ListKit.xcodeproj */; @@ -508,6 +531,7 @@ files = ( 254B3B961D3ABBFF00B1E4F0 /* OctoKit.framework in Embed Frameworks */, 254B3B9A1D3ABC0400B1E4F0 /* RequestKit.framework in Embed Frameworks */, + 66C463FD22270A970006963A /* ReSwiftThunk.framework in Embed Frameworks */, 2565B89F1DE7506C0016371D /* ReSwift.framework in Embed Frameworks */, 7A7A57191C91D78C00670D38 /* ListKit.framework in Embed Frameworks */, 2565B86A1DE74F440016371D /* SAMKeychain.framework in Embed Frameworks */, @@ -557,6 +581,7 @@ 62EF0A801C700D1200D13711 /* Quick.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Quick.xcodeproj; path = Carthage/Checkouts/Quick/Quick.xcodeproj; sourceTree = SOURCE_ROOT; }; 62EF0A9E1C700D1F00D13711 /* Nimble.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Nimble.xcodeproj; path = Carthage/Checkouts/Nimble/Nimble.xcodeproj; sourceTree = SOURCE_ROOT; }; 62EF0AB51C700D4900D13711 /* GitHubAuthSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GitHubAuthSpec.swift; sourceTree = ""; }; + 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "ReSwift-Thunk.xcodeproj"; path = "Carthage/Checkouts/ReSwift-Thunk/ReSwift-Thunk.xcodeproj"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -566,6 +591,7 @@ files = ( 254B3B951D3ABBFF00B1E4F0 /* OctoKit.framework in Frameworks */, 254B3B9D1D3ABC0A00B1E4F0 /* ReSwift.framework in Frameworks */, + 66C463FC22270A970006963A /* ReSwiftThunk.framework in Frameworks */, 254B3B991D3ABC0400B1E4F0 /* RequestKit.framework in Frameworks */, 62C935791C8CD6E500887A23 /* ListKit.framework in Frameworks */, 254B3BA11D3ABC1300B1E4F0 /* ReSwiftRouter.framework in Frameworks */, @@ -733,6 +759,7 @@ 25BB76321C3CBA99008EA13B /* Dependencies */ = { isa = PBXGroup; children = ( + 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */, 253038E91D92D8B900AA49F4 /* SAMKeychain.xcodeproj */, 254B3B7D1D3ABBCE00B1E4F0 /* OctoKit.xcodeproj */, 254B3B651D3ABBC400B1E4F0 /* RequestKit.xcodeproj */, @@ -878,6 +905,15 @@ path = GithubAuthSpec; sourceTree = ""; }; + 66C463F422270A7C0006963A /* Products */ = { + isa = PBXGroup; + children = ( + 66C463F922270A7C0006963A /* ReSwiftThunk.framework */, + 66C463FB22270A7C0006963A /* ReSwift-Thunk-Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -899,6 +935,7 @@ 254B3B9C1D3ABC0400B1E4F0 /* PBXTargetDependency */, 254B3BA01D3ABC0A00B1E4F0 /* PBXTargetDependency */, 254B3BA41D3ABC1300B1E4F0 /* PBXTargetDependency */, + 66C463FF22270A970006963A /* PBXTargetDependency */, ); name = SwiftFlowGitHubBrowser; productName = SwiftFlowGitHubBrowser; @@ -930,7 +967,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Benji Encz"; TargetAttributes = { 25BB761C1C3CB8CB008EA13B = { @@ -976,6 +1013,10 @@ ProductGroup = 254B3B661D3ABBC400B1E4F0 /* Products */; ProjectRef = 254B3B651D3ABBC400B1E4F0 /* RequestKit.xcodeproj */; }, + { + ProductGroup = 66C463F422270A7C0006963A /* Products */; + ProjectRef = 66C463F322270A7C0006963A /* ReSwift-Thunk.xcodeproj */; + }, { ProductGroup = 254B3B4E1D3ABBB400B1E4F0 /* Products */; ProjectRef = 254B3B4D1D3ABBB400B1E4F0 /* ReSwift.xcodeproj */; @@ -1404,6 +1445,20 @@ remoteRef = 62EF0AB11C700D1F00D13711 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 66C463F922270A7C0006963A /* ReSwiftThunk.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = ReSwiftThunk.framework; + remoteRef = 66C463F822270A7C0006963A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 66C463FB22270A7C0006963A /* ReSwift-Thunk-Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "ReSwift-Thunk-Tests.xctest"; + remoteRef = 66C463FA22270A7C0006963A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -1508,6 +1563,11 @@ target = 25BB761C1C3CB8CB008EA13B /* SwiftFlowGitHubBrowser */; targetProxy = 62EF0A7A1C700C2300D13711 /* PBXContainerItemProxy */; }; + 66C463FF22270A970006963A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "ReSwift-Thunk"; + targetProxy = 66C463FE22270A970006963A /* PBXContainerItemProxy */; + }; 7A7A571B1C91D78C00670D38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = ListKit; @@ -1543,13 +1603,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1571,7 +1641,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1588,13 +1658,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_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_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1610,9 +1690,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -1621,36 +1702,34 @@ 25BB76301C3CB8CB008EA13B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)/**", "$(SRCROOT)/Carthage/Build/iOS/**", ); INFOPLIST_FILE = SwiftFlowGitHubBrowser/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Swift-Flow.SwiftFlowGitHubBrowser"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; 25BB76311C3CB8CB008EA13B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)/**", "$(SRCROOT)/Carthage/Build/iOS/**", ); INFOPLIST_FILE = SwiftFlowGitHubBrowser/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Swift-Flow.SwiftFlowGitHubBrowser"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1668,7 +1747,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "de.benjamin-encz.SwiftFlowGitHubBrowserTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftFlowGitHubBrowser.app/SwiftFlowGitHubBrowser"; }; name = Debug; @@ -1686,7 +1765,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "de.benjamin-encz.SwiftFlowGitHubBrowserTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftFlowGitHubBrowser.app/SwiftFlowGitHubBrowser"; }; name = Release; diff --git a/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..949b678 --- /dev/null +++ b/SwiftFlowGitHubBrowser.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/SwiftFlowGitHubBrowser.xcodeproj/xcshareddata/xcschemes/SwiftFlowGitHubBrowser.xcscheme b/SwiftFlowGitHubBrowser.xcodeproj/xcshareddata/xcschemes/SwiftFlowGitHubBrowser.xcscheme index d4c0713..2cac713 100644 --- a/SwiftFlowGitHubBrowser.xcodeproj/xcshareddata/xcschemes/SwiftFlowGitHubBrowser.xcscheme +++ b/SwiftFlowGitHubBrowser.xcodeproj/xcshareddata/xcschemes/SwiftFlowGitHubBrowser.xcscheme @@ -1,6 +1,6 @@ ) -> Action? { - guard case let .loggedIn(configuration) = state.authenticationState.loggedInState else { return nil } +let fetchGitHubRepositories = Thunk { dispatch, getState in + guard case let .loggedIn(configuration)? = getState()?.authenticationState.loggedInState else { return } - Octokit(configuration).repositories { response in + _ = Octokit(configuration).repositories { response in DispatchQueue.main.async { - store.dispatch(SetRepositories(repositories: response)) + dispatch(SetRepositories(repositories: response)) } } - - return nil } diff --git a/SwiftFlowGitHubBrowser/Actions/AuthenticationActions.swift b/SwiftFlowGitHubBrowser/Actions/AuthenticationActions.swift index 590a69d..55f68b9 100644 --- a/SwiftFlowGitHubBrowser/Actions/AuthenticationActions.swift +++ b/SwiftFlowGitHubBrowser/Actions/AuthenticationActions.swift @@ -8,32 +8,33 @@ import ReSwift import ReSwiftRouter +import ReSwiftThunk import OctoKit -func authenticateUser(state: State, store: Store) -> Action? { - guard let config = state.authenticationState.oAuthConfig else { return nil } +let authenticateUser = Thunk { dispatch, getStat in + guard let config = getStat()?.authenticationState.oAuthConfig else { return } let url = config.authenticate() if let url = url { - store.dispatch(SetOAuthURL(oAuthUrl: url)) - store.dispatch(SetRouteAction([loginRoute, oAuthRoute])) + dispatch(SetOAuthURL(oAuthUrl: url)) + dispatch(SetRouteAction([loginRoute, oAuthRoute])) } - - return nil } -func handleOpenURL(url: URL) -> Store.ActionCreator { - return { state, store in - state.authenticationState.oAuthConfig?.handleOpenURL(openUrl: url) { (config: TokenConfiguration) in - AuthenticationService().saveAuthenticationData(config) +func handleOpenURL(url: URL) -> Thunk { + return Thunk { dispatch, getState in + guard let config = getState()?.authenticationState.oAuthConfig else { return } - store.dispatch(UpdateLoggedInState(loggedInState: .loggedIn(config))) - // Switch to the Main View Route - store.dispatch(ReSwiftRouter.SetRouteAction([mainViewRoute])) - } + config.handleOpenURL(openUrl: url) { (config: TokenConfiguration) in + DispatchQueue.main.async { + AuthenticationService().saveAuthenticationData(config) - return nil + dispatch(UpdateLoggedInState(loggedInState: .loggedIn(config))) + // Switch to the Main View Route + dispatch(ReSwiftRouter.SetRouteAction([mainViewRoute])) + } + } } } diff --git a/SwiftFlowGitHubBrowser/AppDelegate.swift b/SwiftFlowGitHubBrowser/AppDelegate.swift index 46b513d..5c85d12 100644 --- a/SwiftFlowGitHubBrowser/AppDelegate.swift +++ b/SwiftFlowGitHubBrowser/AppDelegate.swift @@ -10,8 +10,10 @@ import UIKit import OctoKit import ReSwift import ReSwiftRouter +import ReSwiftThunk -var store = Store(reducer: appReducer, state: nil) +let thunkMiddleware: Middleware = createThunksMiddleware() +var store = Store(reducer: appReducer, state: nil, middleware: [thunkMiddleware]) @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -19,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var router: Router! - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) @@ -48,7 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } - func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool { + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { store.dispatch(handleOpenURL(url: url)) return false diff --git a/SwiftFlowGitHubBrowser/Assets.xcassets/AppIcon.appiconset/Contents.json b/SwiftFlowGitHubBrowser/Assets.xcassets/AppIcon.appiconset/Contents.json index 36d2c80..d8db8d6 100644 --- a/SwiftFlowGitHubBrowser/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/SwiftFlowGitHubBrowser/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", @@ -30,6 +40,16 @@ "size" : "60x60", "scale" : "3x" }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, { "idiom" : "ipad", "size" : "29x29", @@ -59,6 +79,16 @@ "idiom" : "ipad", "size" : "76x76", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/SwiftFlowGitHubBrowser/Services/AuthenticationService.swift b/SwiftFlowGitHubBrowser/Services/AuthenticationService.swift index 53242b9..d57747d 100644 --- a/SwiftFlowGitHubBrowser/Services/AuthenticationService.swift +++ b/SwiftFlowGitHubBrowser/Services/AuthenticationService.swift @@ -32,10 +32,16 @@ extension TokenConfiguration { init(data: Data) { let json: [String: AnyObject] = try! JSONSerialization.jsonObject(with: data, options: []) as! [String : AnyObject] - - self.apiEndpoint = json["endpoint"] as! String - self.accessToken = { if case let s = json["accesstoken"] as? String , s != "null" { return s } else { return nil } }() - self.errorDomain = "OktoKitTokenConfiguration" + let url = json["endpoint"] as! String + let accessToken: String? = { + if case let s = json["accesstoken"] as? String, s != "null" { + return s + } else { + return nil + } + }() + + self.init(accessToken, url: url) } func toData() -> Data { diff --git a/SwiftFlowGitHubBrowser/UIKitExtensions/NavigationController+CompletionBlock.swift b/SwiftFlowGitHubBrowser/UIKitExtensions/NavigationController+CompletionBlock.swift index 1ba995f..ec9b2ab 100644 --- a/SwiftFlowGitHubBrowser/UIKitExtensions/NavigationController+CompletionBlock.swift +++ b/SwiftFlowGitHubBrowser/UIKitExtensions/NavigationController+CompletionBlock.swift @@ -13,7 +13,7 @@ import UIKit extension UINavigationController { func pushViewController(_ viewController: UIViewController, - animated: Bool, completion: @escaping (Void) -> Void) { + animated: Bool, completion: @escaping () -> Void) { CATransaction.begin() CATransaction.setCompletionBlock(completion) @@ -21,7 +21,7 @@ extension UINavigationController { CATransaction.commit() } - func popViewController(_ animated: Bool, completion: @escaping (Void) -> Void) { + func popViewController(_ animated: Bool, completion: @escaping () -> Void) { CATransaction.begin() CATransaction.setCompletionBlock(completion) diff --git a/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift b/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift index 29447ea..74e7259 100644 --- a/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift +++ b/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift @@ -59,7 +59,7 @@ extension BookmarkViewController: UITableViewDelegate { let routeAction = ReSwiftRouter.SetRouteAction(selectedBookmark.route) let setDataAction = ReSwiftRouter.SetRouteSpecificData(route: selectedBookmark.route, - data: selectedBookmark.routeSpecificData) + data: selectedBookmark.routeSpecificData as Any) store.dispatch(setDataAction) store.dispatch(routeAction) diff --git a/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift b/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift index 09d580d..462ad7a 100644 --- a/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift +++ b/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift @@ -47,7 +47,7 @@ class RepositoryDetailViewController: UIViewController, StoreSubscriber { store.unsubscribe(self) } - override func didMove(toParentViewController parent: UIViewController?) { + override func didMove(toParent parent: UIViewController?) { if parent == nil { // Required to update the route, when this VC was dismissed through back button from // NavigationController, since we can't intercept the back button diff --git a/SwiftFlowGitHubBrowserTests/GithubAuthSpec/GitHubAuthSpec.swift b/SwiftFlowGitHubBrowserTests/GithubAuthSpec/GitHubAuthSpec.swift index 968ad0b..ffb8941 100644 --- a/SwiftFlowGitHubBrowserTests/GithubAuthSpec/GitHubAuthSpec.swift +++ b/SwiftFlowGitHubBrowserTests/GithubAuthSpec/GitHubAuthSpec.swift @@ -10,6 +10,8 @@ import Quick import Nimble import ReSwift import OctoKit +import ReSwiftRouter +import ReSwiftThunk @testable import SwiftFlowGitHubBrowser class GitHubAuthSpec: QuickSpec { @@ -18,11 +20,19 @@ class GitHubAuthSpec: QuickSpec { describe("When receiving a success OAuth URL callback ") { - let store = Store(reducer: appReducer, state: nil) + var store: Store! beforeEach { let fakeOAuth = FakeOAuthConfiguration(injectedTokenConfiguration: TokenConfiguration("Token")) - store.state.authenticationState.oAuthConfig = fakeOAuth + let state = State( + navigationState: NavigationState(), + authenticationState: AuthenticationState( + oAuthConfig: fakeOAuth, + oAuthURL: nil, + loggedInState: .notLoggedIn), + repositories: nil, bookmarks: []) + let thunkMiddleware: Middleware = createThunksMiddleware() + store = Store(reducer: appReducer, state: state, middleware: [thunkMiddleware]) let oAuthCallbackURL = URL(string: "swiftflowgithub://success")!