Skip to content

Commit

Permalink
Updated to swift 4.2. Improved current user API client.
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrián Bouza committed Nov 24, 2018
1 parent 33f10c1 commit 0517b46
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0
4.2
13 changes: 12 additions & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ DEPENDENCIES:
- SwiftKeychainWrapper
- VegaScrollFlowLayout

SPEC REPOS:
https://github.com/cocoapods/specs.git:
- Alamofire
- Hero
- Hue
- Kingfisher
- LGButton
- SnapKit
- SwiftKeychainWrapper
- VegaScrollFlowLayout

SPEC CHECKSUMS:
Alamofire: f41a599bd63041760b26d393ec1069d9d7b917f4
Hero: cee286821578e170d8c0c9c9cda7897357401112
Expand All @@ -30,4 +41,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: f6ded6c97ac0c0186c90641c539594a00d275a8f

COCOAPODS: 1.3.1
COCOAPODS: 1.5.3
61 changes: 8 additions & 53 deletions Unsplasher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
3D1E4507203D4FA600886C64 /* photos.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = photos.json; sourceTree = "<group>"; };
3D1E4509203D557B00886C64 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
3D1E450B203D570B00886C64 /* statistics.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = statistics.json; sourceTree = "<group>"; };
3D38BFA021A9334C00CC75A3 /* UnsplasherSDK.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnsplasherSDK.podspec; sourceTree = "<group>"; };
3DA03727203D691700E85963 /* DateFormatterExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormatterExtension.swift; sourceTree = "<group>"; };
3DA03729203D703C00E85963 /* Searches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Searches.swift; sourceTree = "<group>"; };
3DA0372B203D74CC00E85963 /* search_photos.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = search_photos.json; sourceTree = "<group>"; };
Expand Down Expand Up @@ -197,6 +198,7 @@
1041A9D8203AE19900956719 = {
isa = PBXGroup;
children = (
3D38BFA021A9334C00CC75A3 /* UnsplasherSDK.podspec */,
1041A9E4203AE19900956719 /* Unsplasher */,
1041A9EF203AE19900956719 /* UnsplasherTests */,
10564647203C29E000D7D49E /* Example */,
Expand Down Expand Up @@ -386,7 +388,6 @@
1041A9DE203AE19900956719 /* Frameworks */,
1041A9DF203AE19900956719 /* Headers */,
1041A9E0203AE19900956719 /* Resources */,
61F64230DE6F4DD8F4163C30 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand All @@ -406,7 +407,6 @@
1041A9E8203AE19900956719 /* Frameworks */,
1041A9E9203AE19900956719 /* Resources */,
7EC2840C45E6F5A10E283464 /* [CP] Embed Pods Frameworks */,
C57CA495BCBA279907521408 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand All @@ -428,7 +428,6 @@
10564644203C29E000D7D49E /* Resources */,
10564662203C2C2B00D7D49E /* Embed Frameworks */,
0CF99E8B8266BFB8A298CFC7 /* [CP] Embed Pods Frameworks */,
6548BB2FC3BFF98896570CB7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand All @@ -452,11 +451,12 @@
TargetAttributes = {
1041A9E1203AE19900956719 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 0920;
LastSwiftMigration = 1010;
ProvisioningStyle = Automatic;
};
1041A9EA203AE19900956719 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1010;
ProvisioningStyle = Automatic;
};
1041AA01203AF77400956719 = {
Expand Down Expand Up @@ -574,36 +574,6 @@
shellScript = "#!/bin/sh\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal\n# make sure the output directory exists\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\n# Step 1. Build Device and Simulator versions\nxcodebuild -target \"AlamoWater\" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\nxcodebuild -target \"AlamoWater\" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" clean build\n# Step 2. Copy the framework structure (from iphoneos build) to the universal folder\ncp -R \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/AlamoWater.framework\" \"${UNIVERSAL_OUTPUTFOLDER}/\"\n# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory\nSIMULATOR_SWIFT_MODULES_DIR=\"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/AlamoWater.framework/Modules/AlamoWater.swiftmodule/.\"\nif [ -d \"${SIMULATOR_SWIFT_MODULES_DIR}\" ]; then\ncp -R \"${SIMULATOR_SWIFT_MODULES_DIR}\" \"${UNIVERSAL_OUTPUTFOLDER}/AlamoWater.framework/Modules/AlamoWater.swiftmodule\"\nfi\n# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory\nlipo -create -output \"${UNIVERSAL_OUTPUTFOLDER}/AlamoWater.framework/AlamoWater\" \"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/AlamoWater.framework/AlamoWater\" \"${BUILD_DIR}/${CONFIGURATION}-iphoneos/AlamoWater.framework/AlamoWater\"\n# Step 5. Convenience step to copy the framework to the project's directory\ncp -R \"${UNIVERSAL_OUTPUTFOLDER}/AlamoWater.framework\" \"${PROJECT_DIR}\"\n# Step 6. Convenience step to open the project's directory in Finder\nopen \"${PROJECT_DIR}\"";
showEnvVarsInLog = 0;
};
61F64230DE6F4DD8F4163C30 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Unsplasher/Pods-Unsplasher-resources.sh\"\n";
showEnvVarsInLog = 0;
};
6548BB2FC3BFF98896570CB7 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n";
showEnvVarsInLog = 0;
};
72BFF6C1712929F360A6736E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -660,21 +630,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C57CA495BCBA279907521408 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UnsplasherTests/Pods-UnsplasherTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
D825C9EF1118B4DE8C837964 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -912,7 +867,7 @@
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -935,7 +890,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.adboco.Unsplasher;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand All @@ -950,7 +905,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.adboco.UnsplasherTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -965,7 +920,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.adboco.UnsplasherTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand Down
2 changes: 1 addition & 1 deletion Unsplasher/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.4</string>
<string>1.0.5</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
9 changes: 9 additions & 0 deletions Unsplasher/Model/OAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ public struct AccessToken: Codable {
return AccessToken(token: token, tokenType: tokenType, scope: scope)
}

static func remove(from keychain: KeychainWrapper?) {
guard let keychain = keychain else {
return
}
keychain.removeObject(forKey: "token")
keychain.removeObject(forKey: "token_type")
keychain.removeObject(forKey: "scope")
}

}
23 changes: 13 additions & 10 deletions Unsplasher/Unsplash/AuthorizationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Foundation
import WebKit

/// It manages authorization process through a custom view controller
final class AuthorizationManager {
Expand Down Expand Up @@ -43,7 +44,7 @@ final class UnsplashAuthViewController: UIViewController {
/// Completion handler
var completionHandler: (AuthorizationResult) -> Void

let webView = UIWebView()
let webView = WKWebView()

init(url: URL, callbackURLScheme: String, completion: @escaping (AuthorizationResult) -> Void) {
self.authURL = url
Expand All @@ -69,7 +70,7 @@ final class UnsplashAuthViewController: UIViewController {

webView.frame = self.view.frame
webView.backgroundColor = UIColor.white
webView.delegate = self
webView.navigationDelegate = self

self.view.addSubview(webView)

Expand All @@ -82,7 +83,7 @@ final class UnsplashAuthViewController: UIViewController {
])

let urlRequest = URLRequest(url: authURL)
webView.loadRequest(urlRequest)
webView.load(urlRequest)
}

@objc func cancel(sender: UIBarButtonItem) {
Expand All @@ -93,27 +94,29 @@ final class UnsplashAuthViewController: UIViewController {

@objc func refresh(sender: UIBarButtonItem) {
let urlRequest = URLRequest(url: authURL)
webView.loadRequest(urlRequest)
webView.load(urlRequest)
}

}

extension UnsplashAuthViewController: UIWebViewDelegate {
extension UnsplashAuthViewController: WKNavigationDelegate {

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
guard let urlString = request.url?.absoluteString, urlString.starts(with: callbackURLScheme) else {
return true
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let urlString = navigationAction.request.url?.absoluteString, urlString.starts(with: callbackURLScheme) else {
decisionHandler(.allow)
return
}
guard let code = URLComponents(string: urlString)?.queryItems?.first(where: { $0.name == "code" })?.value else {
self.dismiss(animated: true, completion: {
self.completionHandler(.failure(UnsplashError.authorizationError))
})
return true
decisionHandler(.allow)
return
}
self.dismiss(animated: true, completion: {
self.completionHandler(.success(code))
})
return false
decisionHandler(.cancel)
}

}
2 changes: 1 addition & 1 deletion Unsplasher/Unsplash/Requests/CollectionRequests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final public class CollectionRequests: Paginable {
self.manager = manager
}

typealias paginableType = [Collection]
public typealias paginableType = [Collection]

/// Get a single page from the list of all collections
///
Expand Down
95 changes: 94 additions & 1 deletion Unsplasher/Unsplash/Requests/CurrentUserRequests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,23 @@ final public class CurrentUserRequests {

private var manager: Unsplash

private var user: User? {
didSet {
photos.user = user
collections.user = user
}
}

/// Photo related requests
public var photos: CurrentUserPhotosRequests!

/// Collection related requests
public var collections: CurrentUserCollectionsRequests!

init(_ manager: Unsplash) {
self.manager = manager
self.photos = CurrentUserPhotosRequests(manager)
self.collections = CurrentUserCollectionsRequests(manager)
}

/// Get current user's profile
Expand All @@ -27,7 +42,10 @@ final public class CurrentUserRequests {
return
}
let url = Unsplash.baseURLString + "/me"
self.manager.request(url: url, expectedType: User.self, completion: completion)
self.manager.request(url: url, expectedType: User.self) { result in
self.user = result.value
completion(result)
}
}

/// Update current user's profile
Expand Down Expand Up @@ -69,3 +87,78 @@ final public class CurrentUserRequests {
}

}

public class CurrentUserPhotosRequests: Paginable {

internal var user: User?

private var userPhotos: UserPhotosRequests!

init(_ manager: Unsplash) {
self.userPhotos = UserPhotosRequests(manager)
}

public typealias paginableType = [Photo]

/// Get user photos
///
/// - Parameters:
/// - page: Page
/// - perPage: Number of photos per page
/// - orderBy: Order
/// - stats: Show the stats for each user’s photo
/// - resolution: The frequency of the stats
/// - quantity: The amount of for each stat
/// - completion: Completion handler
public func get(page: Int? = nil, perPage: Int? = nil, orderBy: Unsplash.OrderBy? = .popular, stats: Bool? = false, resolution: Unsplash.StatisticsResolution? = nil, quantity: UInt32 = 30, completion: @escaping (PhotoListResult) -> Void) {
guard let username = user?.username else {
completion(.failure(UnsplashError.userProfileNeeded))
return
}
self.userPhotos.by(username, page: page, perPage: perPage, orderBy: orderBy, stats: stats, resolution: resolution, quantity: quantity, completion: completion)
}

/// Get photos liked by the user
///
/// - Parameters:
/// - page: Page
/// - perPage: Number of photos per page
/// - orderBy: Order
/// - completion: Completion handler
public func liked(page: Int?, perPage: Int?, orderBy: Unsplash.OrderBy?, completion: @escaping (PhotoListResult) -> Void) {
guard let username = user?.username else {
completion(.failure(UnsplashError.userProfileNeeded))
return
}
self.userPhotos.liked(by: username, page: page, perPage: perPage, orderBy: orderBy, completion: completion)
}

}

public class CurrentUserCollectionsRequests: Paginable {

internal var user: User?

private var userCollections: UserCollectionsRequests!

init(_ manager: Unsplash) {
self.userCollections = UserCollectionsRequests(manager)
}

public typealias paginableType = [Collection]

/// Get list of collections created by the user
///
/// - Parameters:
/// - page: Page
/// - perPage: Number of collections per page
/// - completion: Completion handler
public func get(page: Int?, perPage: Int?, completion: @escaping (CollectionListResult) -> Void) {
guard let username = user?.username else {
completion(.failure(UnsplashError.userProfileNeeded))
return
}
self.userCollections.by(username, page: page, perPage: perPage, completion: completion)
}

}
Loading

0 comments on commit 0517b46

Please sign in to comment.