Clean up of view, passing back scopes, add icon

This commit is contained in:
IamTheFij 2018-01-19 19:46:40 -08:00
parent 4b3e0898c7
commit bb34a2635f
7 changed files with 80 additions and 36 deletions

View File

@ -31,13 +31,15 @@
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-180.png",
"scale" : "3x"
},
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -27,14 +27,14 @@
</navigationBar>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Logged In" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CoH-cd-flw">
<rect key="frame" x="38" y="99" width="298" height="45"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="37"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="IdY-jU-MBP">
<rect key="frame" x="16" y="152" width="343" height="495"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<rect key="frame" x="16" y="152" width="343" height="305"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
@ -44,7 +44,7 @@
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" notEnabled="YES"/>
</accessibility>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<viewLayoutGuide key="safeArea" id="OGN-ry-fYp"/>
</view>
<connections>
<outlet property="loggedIn" destination="CoH-cd-flw" id="SUh-wA-KNF"/>

View File

@ -15,6 +15,7 @@ import OAuthSwiftAlamofire
class FitbitClient {
private enum FitKitRequestError: Error {
case unableToParseResults
case invalidAuthorization
}
private var oauthClient: OAuth2Swift
@ -24,6 +25,7 @@ class FitbitClient {
private let authorizeUrl = "https://www.fitbit.com/oauth2/authorize"
private let accessTokenUrl = "https://api.fitbit.com/oauth2/token"
private var keychainWrapper: KeychainWrapper
private let keychainCredKey = "credential"
init() {
// Init inner client
@ -44,10 +46,11 @@ class FitbitClient {
self.keychainWrapper = KeychainWrapper.standard
// Attempt to load tokens
self.loadStoredTokens()
self.maybeLoadStoredCredential()
}
func loadStoredTokens() {
/// Attempts to load and use stored credentials
func maybeLoadStoredCredential() {
if let credential = self.readCredential() {
NSLog("Using credential from Keychain")
self.oauthClient.client.credential.oauthToken = credential.oauthToken
@ -55,8 +58,11 @@ class FitbitClient {
}
}
/// Attempts to read OAuthSwiftCredential from the keychain
///
/// - Returns: If a valid credential is found, it will be returned
func readCredential() -> OAuthSwiftCredential? {
if let credential = self.keychainWrapper.object(forKey: "credential") as? OAuthSwiftCredential {
if let credential = self.keychainWrapper.object(forKey: keychainCredKey) as? OAuthSwiftCredential {
NSLog("Found credential in keychain")
return credential
}
@ -64,8 +70,19 @@ class FitbitClient {
return nil
}
/// Persists an OAuthSwiftCredential into the keychain
///
/// - Parameter credential: credential to be persisted
/// - Returns: TRUE if persisted successfully
private func storeCredential(_ credential: OAuthSwiftCredential) -> Bool {
return self.keychainWrapper.set(credential, forKey: "credential")
return self.keychainWrapper.set(credential, forKey: keychainCredKey)
}
/// Clears credential token and expiration
func clearCredential() {
self.oauthClient.client.credential.oauthToken = ""
self.oauthClient.client.credential.oauthTokenExpiresAt = nil
self.keychainWrapper.removeObject(forKey: keychainCredKey)
}
/// Check if the current client is already authorized
@ -90,12 +107,13 @@ class FitbitClient {
/// - viewController: the source controller to create the new Safari view
/// - success: Callback to be executed on success
/// - failure: Callback to be executed on failure
func authorize(viewController: UIViewController, success: @escaping () -> Void, failure: @escaping () -> Void) {
func authorize(viewController: UIViewController, callback: @escaping (String?, Error?) -> Void) {
// Set webview handler
self.oauthClient.authorizeURLHandler = SafariURLHandler(
viewController: viewController,
oauthSwift: self.oauthClient
)
// Authorize
let _ = self.oauthClient.authorize(
withCallbackURL: URL(string: self.callbackUrl)!,
@ -108,19 +126,18 @@ class FitbitClient {
let scope = parameters["scope"] as? String
else {
NSLog("Invalid authorization response")
failure()
callback(nil, FitKitRequestError.invalidAuthorization)
return
}
NSLog("Authorized scope: \(scope)")
NSLog("Succesfully authenticated with credentials \(credential.oauthToken)")
let _ = self.storeCredential(credential)
success()
callback(scope, nil)
},
failure: {
error in
// TODO: Maybe return the error
NSLog(error.localizedDescription)
failure()
NSLog("Error authorizing \(error.localizedDescription)")
callback(nil, error)
}
)
}

View File

@ -23,7 +23,7 @@ class ViewController: UIViewController {
}
override func viewDidAppear(_ animated: Bool) {
authorize()
ensureAuthorized(callback: self.updateView)
}
override func didReceiveMemoryWarning() {
@ -34,35 +34,53 @@ class ViewController: UIViewController {
fileprivate func updateAuthorizedLabel() {
if self.client.isAuthorized() {
self.loggedIn.text = "Logged In"
//self.loginButton.currentTitle = "Log Out"
} else {
self.loggedIn.text = "Not Logged In"
//self.loginButton.currentTitle = "Log In"
}
}
fileprivate func authorize() {
/// Ensure that the client is authorized and then continue
fileprivate func ensureAuthorized(callback: @escaping (Bool) -> Void) {
// If already authroized, we can short circuit
if self.client.isAuthorized() {
callback(true)
return
}
// Authorize the client
self.client.authorize(viewController: self) {
scope, error in
if error != nil {
NSLog("Error encountered when attempting authorization: \(error.debugDescription)")
}
guard let scope = scope else {
NSLog("Did not retreive any authorized scope")
callback(false)
return
}
NSLog("Authorized for scope: \(scope). Requesting HealthKit access")
HealthKitHelper.authorizeHealthKit() {
result, error in
// TODO: Do something with the result and error
if !self.client.isAuthorized() {
self.client.authorize(viewController: self, success: self.authorized, failure: self.unauthroized)
if error != nil {
callback(false)
} else {
// TODO: this should be made significantly more clear
self.displayWeight()
callback(true)
}
}
}
}
fileprivate func authorized() {
NSLog("We have Fitbit auth!!!")
updateAuthorizedLabel()
self.displayWeight()
fileprivate func updateView(authSuccess: Bool) {
self.updateAuthorizedLabel()
if authSuccess {
self.syncWeights()
}
}
fileprivate func unauthroized() {
NSLog("No auth. Booo!!!")
}
func displayWeight() {
/// Synchronizes weights from Fitbit to HealthKit
func syncWeights() {
let today = Date()
let lastMonth = Calendar.current.date(byAdding: .day, value: -31, to: today)!
self.client.getWeight(start: lastMonth, end: today) {
@ -70,6 +88,7 @@ class ViewController: UIViewController {
fbWeights, error in
if let error = error {
NSLog("Unable to get weights: \(error)")
self.outputText.text = "Error getting weights"
return
}