From a1b059641cdcef8ad622d396d63252556cbba1d7 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Thu, 20 Oct 2016 08:22:51 -0500 Subject: [PATCH 01/11] Add keyboard avoiding code. --- Cely.xcodeproj/project.pbxproj | 4 +++ Cely/Cely.storyboard | 15 +++++---- Cely/CelyLoginViewController.swift | 54 +++++++++++++++++++++++++++++- CelyTests/LoginStyleTests.swift | 46 +++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 CelyTests/LoginStyleTests.swift diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index 6ba6db9..ded9bf5 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 31358EB41DB31BC400AC7119 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 31358EB21DB31BC400AC7119 /* LaunchScreen.storyboard */; }; 31358EC51DB31D3300AC7119 /* Locksmith.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31358EC41DB31D3300AC7119 /* Locksmith.framework */; }; 31358EC61DB31D3300AC7119 /* Locksmith.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 31358EC41DB31D3300AC7119 /* Locksmith.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 315D44661DB8F47B00A21DC1 /* LoginStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315D44651DB8F47B00A21DC1 /* LoginStyleTests.swift */; }; 317516421DB7BD9D00974002 /* TestStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 317516401DB7B23C00974002 /* TestStoryboard.storyboard */; }; 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */; }; /* End PBXBuildFile section */ @@ -110,6 +111,7 @@ 31358EB91DB31BDE00AC7119 /* Cely Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Cely Demo.entitlements"; sourceTree = ""; }; 31358EBF1DB31CA800AC7119 /* Locksmith.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Locksmith.framework; sourceTree = ""; }; 31358EC41DB31D3300AC7119 /* Locksmith.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Locksmith.framework; path = "Cely Demo/Locksmith.framework"; sourceTree = ""; }; + 315D44651DB8F47B00A21DC1 /* LoginStyleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginStyleTests.swift; sourceTree = ""; }; 317516401DB7B23C00974002 /* TestStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = TestStoryboard.storyboard; path = ../CelyTests/Frameworks/TestStoryboard.storyboard; sourceTree = ""; }; 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyWindowManagerTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -183,6 +185,7 @@ isa = PBXGroup; children = ( 1FB2B23E1DB1751600716E80 /* CelyTests.swift */, + 315D44651DB8F47B00A21DC1 /* LoginStyleTests.swift */, 1F0C13341DB188AB00AC1C94 /* CelyStorageTests.swift */, 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */, 1FB2B2401DB1751600716E80 /* Info.plist */, @@ -415,6 +418,7 @@ buildActionMask = 2147483647; files = ( 1F0C13351DB188AB00AC1C94 /* CelyStorageTests.swift in Sources */, + 315D44661DB8F47B00A21DC1 /* LoginStyleTests.swift in Sources */, 1FB2B23F1DB1751600716E80 /* CelyTests.swift in Sources */, 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */, ); diff --git a/Cely/Cely.storyboard b/Cely/Cely.storyboard index ee543d3..2a774dc 100644 --- a/Cely/Cely.storyboard +++ b/Cely/Cely.storyboard @@ -24,6 +24,11 @@ + @@ -36,25 +41,21 @@ - + - - + + diff --git a/Cely/CelyLoginViewController.swift b/Cely/CelyLoginViewController.swift index c659b53..b46e630 100644 --- a/Cely/CelyLoginViewController.swift +++ b/Cely/CelyLoginViewController.swift @@ -15,7 +15,7 @@ class CelyLoginViewController: UIViewController { @IBOutlet weak var passwordField: UITextField? @IBOutlet weak var loginButton: UIButton? @IBOutlet var textFields: [UITextField]? - + @IBOutlet fileprivate weak var bottomLayoutConstraint: NSLayoutConstraint! // MARK: - Variables @@ -28,6 +28,17 @@ class CelyLoginViewController: UIViewController { loginButton?.addTarget(self, action: #selector(didPressLogin), for: .touchUpInside) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setUpKeyboardNotification() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + func didPressLogin() { if let fields = textFields, fields.flatMap({$0}).reduce(true, {$0 && !$1.text!.isEmpty}) { @@ -46,6 +57,47 @@ class CelyLoginViewController: UIViewController { } } +internal extension CelyLoginViewController { + + func keyboardWillShowNotification(notification: NSNotification) { + updateBottomLayoutConstraintWithNotification(notification: notification) + } + + func keyboardWillHideNotification(notification: NSNotification) { + updateBottomLayoutConstraintWithNotification(notification: notification) + } + + // MARK: - Private + + fileprivate func setUpKeyboardNotification() { + NotificationCenter.default + .addObserver(self, selector: #selector(keyboardWillShowNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default + .addObserver(self, selector: #selector(keyboardWillHideNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + + fileprivate func updateBottomLayoutConstraintWithNotification(notification: NSNotification) { + let userInfo = notification.userInfo! + + guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, + let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue, + let rawCurve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as? NSNumber else { return } + + let animationDuration = (duration).doubleValue + let keyboardEndFrame = (endFrame).cgRectValue + let convertedKeyboardEndFrame = view.convert(keyboardEndFrame, from: view.window) + let rawAnimationCurve = (rawCurve).uint32Value << 16 + let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) + + let newConstraint = view.bounds.maxY - convertedKeyboardEndFrame.minY + bottomLayoutConstraint.constant = newConstraint == 0 ? 206 : newConstraint + + UIView.animate(withDuration: animationDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { + self.view.layoutIfNeeded() + }, completion: nil) + } +} + extension CelyLoginViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { diff --git a/CelyTests/LoginStyleTests.swift b/CelyTests/LoginStyleTests.swift new file mode 100644 index 0000000..079b088 --- /dev/null +++ b/CelyTests/LoginStyleTests.swift @@ -0,0 +1,46 @@ +// +// LoginStyleTests.swift +// Cely +// +// Created by Fabian Buentello on 10/20/16. +// Copyright © 2016 Fabian Buentello. All rights reserved. +// + +import XCTest + +class LoginStyleTests: XCTestCase { + + override func setUp() { + super.setUp() + + } + + override func tearDown() { + + super.tearDown() + } + + func testBackgroundColor() { + + } + + func testTextfieldShadowColor() { + + } + + func testTextfieldLeftRightMargin() { + + } + + func testTextfieldBottomMargin() { + + } + + func testAppImage() { + + } + + func testFooterView() { + + } +} From 6d1fe6e3c068f5f6642cef82cd71bd5c074daae7 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Fri, 4 Nov 2016 20:21:16 -0500 Subject: [PATCH 02/11] start to add style to CelyLoginViewController --- Cely/Cely.storyboard | 36 ++++++++++++++++---- Cely/CelyConstants.swift | 16 +++++++++ Cely/CelyLoginViewController.swift | 53 ++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 7 deletions(-) diff --git a/Cely/Cely.storyboard b/Cely/Cely.storyboard index ee543d3..3393930 100644 --- a/Cely/Cely.storyboard +++ b/Cely/Cely.storyboard @@ -1,5 +1,5 @@ - + @@ -26,31 +26,53 @@ - + + + + + + + + + + - + + + + + + + + + + - + - - + + + @@ -64,7 +86,7 @@ - + diff --git a/Cely/CelyConstants.swift b/Cely/CelyConstants.swift index 949a89c..0824502 100644 --- a/Cely/CelyConstants.swift +++ b/Cely/CelyConstants.swift @@ -60,3 +60,19 @@ public protocol CelyStorageProtocol { func get(_ key: String) -> Any? func removeAllData() } + +internal extension UITextField { + + @IBInspectable var leftSpacer: CGFloat { + get { + if let l = leftView { + return l.frame.size.width + } else { + return 0 + } + } set { + leftViewMode = .always + leftView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height)) + } + } +} diff --git a/Cely/CelyLoginViewController.swift b/Cely/CelyLoginViewController.swift index d862f1e..0cb2e62 100644 --- a/Cely/CelyLoginViewController.swift +++ b/Cely/CelyLoginViewController.swift @@ -15,6 +15,7 @@ class CelyLoginViewController: UIViewController { @IBOutlet weak var passwordField: UITextField? @IBOutlet weak var loginButton: UIButton? @IBOutlet var textFields: [UITextField]? + @IBOutlet fileprivate weak var bottomLayoutConstraint: NSLayoutConstraint! // MARK: - Variables @@ -28,6 +29,17 @@ class CelyLoginViewController: UIViewController { loginButton?.addTarget(self, action: #selector(didPressLogin), for: .touchUpInside) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setUpKeyboardNotification() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + func didPressLogin() { if let username = usernameField?.text, let password = passwordField?.text { Cely.loginCompletionBlock?(username, password) @@ -38,6 +50,47 @@ class CelyLoginViewController: UIViewController { } } +internal extension CelyLoginViewController { + + func keyboardWillShowNotification(notification: NSNotification) { + updateBottomLayoutConstraintWithNotification(notification: notification) + } + + func keyboardWillHideNotification(notification: NSNotification) { + updateBottomLayoutConstraintWithNotification(notification: notification) + } + + // MARK: - Private + + fileprivate func setUpKeyboardNotification() { + NotificationCenter.default + .addObserver(self, selector: #selector(keyboardWillShowNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default + .addObserver(self, selector: #selector(keyboardWillHideNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + } + + fileprivate func updateBottomLayoutConstraintWithNotification(notification: NSNotification) { + let userInfo = notification.userInfo! + + guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, + let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue, + let rawCurve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as? NSNumber else { return } + + let animationDuration = (duration).doubleValue + let keyboardEndFrame = (endFrame).cgRectValue + let convertedKeyboardEndFrame = view.convert(keyboardEndFrame, from: view.window) + let rawAnimationCurve = (rawCurve).uint32Value << 16 + let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) + + let newConstraint = view.bounds.maxY - convertedKeyboardEndFrame.minY + bottomLayoutConstraint.constant = newConstraint == 0 ? 206 : newConstraint + + UIView.animate(withDuration: animationDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { + self.view.layoutIfNeeded() + }, completion: nil) + } +} + extension CelyLoginViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { From 27549112cd2c3ad7ce0e990b68464e7461814545 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Fri, 4 Nov 2016 20:45:00 -0500 Subject: [PATCH 03/11] Add Logos and create CelyProtocols --- .../AppIcon.appiconset/Contents.json | 25 +++++++++++++++ .../CelyThin.imageset/CelyThin.png | Bin 0 -> 18104 bytes .../CelyThin.imageset/CelyThin@2x.png | Bin 0 -> 40824 bytes .../CelyThin.imageset/Contents.json | 22 +++++++++++++ .../ChaiOne Logo.imageset/511993.png | Bin 0 -> 9181 bytes .../ChaiOne Logo.imageset/Contents.json | 21 ++++++++++++ Cely Demo/Assets.xcassets/Contents.json | 6 ++++ Cely.xcodeproj/project.pbxproj | 8 +++++ Cely/Cely.storyboard | 30 +++++++++++------- Cely/CelyConstants.swift | 26 ++++----------- Cely/CelyProtocols.swift | 24 ++++++++++++++ .../CelyLogo.imageset/CelyThin.png | Bin 0 -> 18104 bytes .../CelyLogo.imageset/CelyThin@2x.png | Bin 0 -> 40824 bytes .../CelyLogo.imageset/Contents.json | 22 +++++++++++++ .../ChaiOne Logo.imageset/511993.png | Bin 0 -> 9181 bytes .../ChaiOne Logo.imageset/Contents.json | 21 ++++++++++++ .../Assets.xcassets/Contents.json | 6 ++++ 17 files changed, 181 insertions(+), 30 deletions(-) create mode 100644 Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin.png create mode 100644 Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin@2x.png create mode 100644 Cely Demo/Assets.xcassets/CelyThin.imageset/Contents.json create mode 100644 Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/511993.png create mode 100644 Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/Contents.json create mode 100644 Cely Demo/Assets.xcassets/Contents.json create mode 100644 Cely/CelyProtocols.swift create mode 100644 Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin.png create mode 100644 Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin@2x.png create mode 100644 Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json create mode 100644 Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/511993.png create mode 100644 Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/Contents.json create mode 100644 Cely/Supporting Files/Assets.xcassets/Contents.json diff --git a/Cely Demo/Assets.xcassets/AppIcon.appiconset/Contents.json b/Cely Demo/Assets.xcassets/AppIcon.appiconset/Contents.json index 36d2c80..1d060ed 100644 --- a/Cely Demo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Cely Demo/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,11 @@ "idiom" : "ipad", "size" : "76x76", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" } ], "info" : { diff --git a/Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin.png b/Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin.png new file mode 100644 index 0000000000000000000000000000000000000000..636a5ac2268d82afefc543bd5884139114a902e3 GIT binary patch literal 18104 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 JtaD0e0sx`KWn=&V literal 0 HcmV?d00001 diff --git a/Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin@2x.png b/Cely Demo/Assets.xcassets/CelyThin.imageset/CelyThin@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b7b5f363e331202c75f8827042b4eab5fc3ed1e5 GIT binary patch literal 40824 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 YM!bk{e80c^V=C}>38|}Aa=|L#KloENRsaA1 literal 0 HcmV?d00001 diff --git a/Cely Demo/Assets.xcassets/CelyThin.imageset/Contents.json b/Cely Demo/Assets.xcassets/CelyThin.imageset/Contents.json new file mode 100644 index 0000000..9af9c85 --- /dev/null +++ b/Cely Demo/Assets.xcassets/CelyThin.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "CelyThin.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "CelyThin@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/511993.png b/Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/511993.png new file mode 100644 index 0000000000000000000000000000000000000000..e58c1d376b4c4b509c90de730da938fb7b0cda6d GIT binary patch literal 9181 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 - + @@ -19,23 +19,27 @@ - + - + + + + + - + + + + + @@ -45,10 +49,11 @@ - - + + - + + @@ -68,4 +73,7 @@ + + + diff --git a/Cely/CelyConstants.swift b/Cely/CelyConstants.swift index 064900d..628fd5b 100644 --- a/Cely/CelyConstants.swift +++ b/Cely/CelyConstants.swift @@ -21,10 +21,13 @@ public enum CelyStatus: CelyCommands { case LoggedOut = "CelyStatus.LoggedOut.user" } -/// Protocol for model class to implements -public protocol CelyUser { - /// Enum of all the properties you would like to save for a model - associatedtype Property : RawRepresentable +/// Options that you can pass into Cely on `Cely.setup(_:)` +public enum CelyOptions { + case Storage + case HomeStoryboard + case LoginStoryboard + case LoginCompletionBlock + case LoginStyle } // enum result on whether or not Cely successfully saved your data @@ -45,18 +48,3 @@ public func == (lhs: StorageResult, rhs: StorageResult) -> Bool { return false } } - -/// Options that you can pass into Cely on `Cely.setup(_:)` -public enum CelyOptions { - case Storage - case HomeStoryboard - case LoginStoryboard - case LoginCompletionBlock -} - -/// Protocol a storage class must abide by in order for Cely to use it -public protocol CelyStorageProtocol { - func set(_ value: Any?, forKey key: String, securely secure: Bool) -> StorageResult - func get(_ key: String) -> Any? - func removeAllData() -} diff --git a/Cely/CelyProtocols.swift b/Cely/CelyProtocols.swift new file mode 100644 index 0000000..449b088 --- /dev/null +++ b/Cely/CelyProtocols.swift @@ -0,0 +1,24 @@ +// +// CelyProtocols.swift +// Cely +// +// Created by Fabian Buentello on 11/4/16. +// Copyright © 2016 Fabian Buentello. All rights reserved. +// + +import Foundation + +/// Protocol for model class to implements +public protocol CelyUser { + /// Enum of all the properties you would like to save for a model + associatedtype Property : RawRepresentable +} + +/// Protocol a storage class must abide by in order for Cely to use it +public protocol CelyStorageProtocol { + func set(_ value: Any?, forKey key: String, securely secure: Bool) -> StorageResult + func get(_ key: String) -> Any? + func removeAllData() +} + +public protocol CelyStyle {} diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin.png b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin.png new file mode 100644 index 0000000000000000000000000000000000000000..636a5ac2268d82afefc543bd5884139114a902e3 GIT binary patch literal 18104 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 JtaD0e0sx`KWn=&V literal 0 HcmV?d00001 diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin@2x.png b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b7b5f363e331202c75f8827042b4eab5fc3ed1e5 GIT binary patch literal 40824 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 YM!bk{e80c^V=C}>38|}Aa=|L#KloENRsaA1 literal 0 HcmV?d00001 diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json new file mode 100644 index 0000000..9af9c85 --- /dev/null +++ b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "CelyThin.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "CelyThin@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/511993.png b/Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/511993.png new file mode 100644 index 0000000000000000000000000000000000000000..e58c1d376b4c4b509c90de730da938fb7b0cda6d GIT binary patch literal 9181 zcmbt)WmlBl`}Q?-OGyshf^-bsFtiLvi@o~JXz*lN;b;V~{!0q@p^W;%nCXQY<7!8}48Tx;n{P^5OO3K4I=g@a8iCO*klj|6L4s*Du^|dsHknd^Tx_N()RlC)EHM)cVd8#nxTi zKK;IU|KNtfjRx?_m?4U<*otoj5^ijLg zwXYI7ZBNF==gnU7=C@=_bWNLsIy-jt0;b~5H^Z3U0{67EMn}Gh>Q`18=P}}s9^IoFCiPVNpgND;6?hwG+!%e@6N^r$j!L-@z1`)$} zM($3^>4w*Xk3RrVr6$*-o!)fQrN?8*u-M0$h{eNuTEC|P0ju5Jumk&1+bPmWPu+wc zFljkvfhedq&ws*cD#pckjXg2a)9+f(z?|Z({hAv$dG!dzojIrWP|CaX`I^<97g{FK zbA&(wOzNqd&H0XwOLTi7(Dpz5Qglyz=C6T89T2_%N^Ta4T_RZ!urVXA$(+|Dv@NBIjmD(06TVr7Qo7hW2F?(I!OkpZ7;y>K)+k6LSY z8H^QiykE}Q6xbaeoeSGktW43c2ZCzs@KgzeRpBW=-Go16s56DmC_3GvDHPI1B$rw# z*g~9B5%~2oBPShYQtFWe+dFKLvXlIk2KAdLGLeZd0{@*gwAY-h?;fu-{}3ZF4PwE)>Iw;X{sE~HG< z-C8Ci^QJ34RS~E~A>NiJx@DvV(Wh>Qh)4$)LFpLP4?R zf@E>Sq$J}RtUzx8au#p4`d~(EpFXj_?vF}I3MZj-jMTwRp!v?E2rqG(^P^^Yr8tdd zdtrp{6`M{U1bT&|`Em7pu0cBB4%dmc(c*8;U_42!o0EAqc61~@8XYfJQQ`wVue`vj zqE)uiG1H+6Oo#utXt|_o@(wO4N36?>kkOR1 zv}_31%Bv($b@CrFQpkL;CB!$Wc~Kw*PBrLpF$Xwg#O-}o_k=f|Xzgg~Y#5rXULe2VeU$n?SrJc0 z{j{>v>ZjijqsirPvwHRKR^F+)KMSz&*njFw9a>tvAsO-MuO%auk@CJ^a{AZcL9Krx z&VQBDbbD7t7848*7r`|L5pjYjiPY=~Q9+;3a`!`=uU8UdKHG9i!qj=|RaImE_64m% z!elv!R8=i941RLk(#K2rhjGu#VGhiXHSpX`)bd2z`(2HEVAGn`jFK_8i{k3Yt{ZLS zB+d9e8ku7`1n#uuVByaQSO{hmIJLajY47)YdaI^}-ER1xOERD;#Xc0XMcZuz0Jr1i zu@yICSLsgkzBlujJNvEBDKbl?B5+~Sl(yF5(G<{GUqk%E?|^?HIdl&*E@#>RtOF1& zj0%8r^sVmOVh%+=EGB6v_hfL-?(*8i)rn+Mo>WMA4+`-7ba~uTKXPcEClI_ugM%+*a3(BMy1YEfI=Ij-ZBHD!Mf2o+!vo zaK>svl_`BRl1EPU)?Wa3tXIZz9XNkFsqkIO`x$WS>l+IWbjobnn4^N7kHsIVmHFHC zb8grD67IGuDkH3BGAt86Sk$WVauk*hy)>NHzT{5Tl*2YMf#S%Jb0p*>;;=AY zQ_6YA??S@HGBPaIz`bnq|iIXo{vXNZfCPL?@=tb7k5MHZf7{>PQ<)#YMR7e^orM^5pc+D z4>-gD2?OrGEiw*?RdQ#buM)!zzI`ay<-b$f0{fdpK*>PzL*aBUr}XE&SZB3N{osG% z%XtES;S%tx=jTJe7XQc0w5Y9@`>vZeZve=@&Nwq1`3w0*-ZeFy>MuKT?hZ>UFtU2V zr}(n{`(Qz!*QVF+wDPer%V^uLzbV#!)j?IN&LS6o+~Lr3&PnMv-39$Ktv^^Nl7`42 zKhZB6p>H{}n6#tsDF&BS0Pw)KZAMewF<`SA{Wv|C+O^PhLFWREM<|V~2i4~YS!_>~ zaci_RkM@sRSgF+(Cz*zEfVq`K(_=m7dr9XT)sbE2U{uGr#;(Q;42pKeoId`AI!;o$ z(9desrs?KQY-J0Z8;zL?-WrZrkwo&<>E#buU1%0=R0H>|G@UwF%#%GuxN+@gvZHMQ zBi5#?A}&Yvx`oHQrGAn$D%yGZ#BSxr1GVp3V8f>8?0fBMdzR#o#wi-;eHNF8n4M;` z94*@x$BZeV(03MFj(X)x(b4FB#UwuT_;=|u?fv}DR9ig%Hal@W4^tauOG{mYmR?w)KM z|4E!g-GVnr{@D1ug6Sw8;Od!5F~ri{;vpm%&!nn|oX1x&{F~$z{CocD-S16OcnS#N ziTFCIMh>SF5%$AkJq(_}8WctUa4oWL^AV*i!lF;ZNKxj?r>(a|B>wLsX`xrE97$4AG(7* z9LJjI`F{`?V(~u42Uc0>PrWTGtj=YP6@*hF$iX91Vbai4<9NV1N0TBE5ESp~Vc7+$ zhRqE-RcYbJIqas#%p6v&B!cZBdh+6Mo4$a6UqRFKY3)3m=#gcQiKOZO=@<&Heq`t=V=SrtBA-8q>F#0petc{gYTSN8KoF5MI902fY+zT%H=4eX&3bA zg06e_n-?s$H~79AC2J7=D7qu0v0MHQRvAdC8FKy^B`(UzXKVO<>-o<9!tI^KJ9vlY zp^vY)dR*0ew?-6od$1(^$^>(f#NL@_pK}{V#tMZ9b>aN9fo0$eWpsDl@2M8inBOQyN{&X9I<`1mgDKXNnUvOT z1@^ESFJh9#B=X>htKTP&TV-rshj;s}hDsJ>RH`0xJ6}sP+miqS&+>$fwAWjFc4n*i zW;`+^03FCi8qqwPX3fv9%4*o!j6{J9vqfc{CH0E}Rd| zj2n>ISZy6OP3T{t!wLdwQgEBLa5cu)>)i?RHSpbrr1bslnVxdCA{Bm~H7bD{4$_gv zwn6*mB9j1>ZC>MW-te`v2BI3j!wUF`;w>%{24rEJ;q@u)eiZuq&*NWPI$&@2*FQPn zuC^N(H9y5+*xVppM377vd--u^wSzuCQP`wz!%wg9iooBNEmt*yOX=Y{hMj?H|C zY8nMz0qB=0poQ8>)VIs0_i@ZL z5|)9v7kyjY3M>e=@0L#0y8W_0Vo1@efX5Hk#@rw_y}mQB4%OvT{=>*V03?w61Egfd zTe-3Wm9oT}Ea*Oak|QA|e!udppOK&kcH@;OUM{**@NkOuSFeU(y&mS2e>4i@s1F@- z=wbWOAB0lM*2wng*7uTK+rlNR&gf??j^^E*w}+P>U`<7$5vL* zRXB-|2IfaXgi?&%bHytDC)aG)@hcCe`$KMvz|_}xME zUj52@2~m-sx|O3Z?yAwvt6eDS63A<_3_CD7c%%cx!C&Y*x z@M%VV!wXK7((Np{M{4>fY}RNsTszMiG^uljtsN~no2Z=jxlI8TAm@YNs5b@U^urm4 z2dR<*J3BL5U5wW*u?6Z_1Sl@cg>%>buFb*?%arx5u5Sub@DhGd)+8Dg=5Ve(+5+#< zodv#k=DSuXTeU!x;hITvKW_ch*PlTWz!HJQZXMF$>3Fw-+2nu08O2&ysGK@e&0--K zdrhC5cbxmET^E1AOH8{;BbL7t-oub6$IKbyxM)+vZHI>nOXsKvIH;L{(*9sTlP}7^}g;KA-GOoKymX zl*5hySd?HA@~XInogG)^>FW1;ZfS_e2IGMr0Twf!!#2A*=C?@86J<|~v3|RsDOv#$i#9hUGjAgvsB3@x) zJ%4IpvWP90fDMRn*^1>xBPpw%baLA8*ciNfbY*ugcUW}mVz75b&iTfKib1?&Ne>VS z4S(yYmH&DJa*Rp=dM z&mtAb(`|Gl-`vmGxCq)ii)LKpnrh;Ks#oUy?}F!>kf@IMTj^jf20r#h0|IA*37)a# zJs~0;z_DW( zRH!s58mXx>cBb|k`<)#^hdS}Ks!RM-YM5yYhY6|X47pqA5i?DH#GP%%U_fOs?;l(c zPsjLEm@O$*Q?=1k<_T@yZ>+6ZHe6pZ`>oe6O16Milp@-=`UC~FB4GAcO$sZgg9=?Q){J5xSYEm+-&62qFhBw zebDs#63#7TNn5AlWp0mvE`PLvdn7}UnV13B1&Qr0yXn?5spLK{zQ#So+9<_2Hx}*< z+(TD#v1u?brp!Nk*}=DE!A1P%&lOMiI${6g+Vrp?9+zv{8(pkk3gY>}Zz!Kzm8DFf zD&d=prcB~~#UF`E;G#9|FAyZ& zzV@Go&Bxh9DUtWm-BLK^BxOa+9wh#Rau)+Z>lwR8k?zguI+4&MT(srEjsOn9$hVbq zob^q2k;6Lu?SGxq8@Li2V&Is;TjW@$76LElU7t~k38&)LL_Nn{jzcO+l|b1c*r5y= zv6-*mP>0rg>vm;e2djS}!t+*rQ#Xgoa)0ZP-xp6+`nKW;unUn_v z4Us6*dYHN>E*Sy&L8%P+?!St^g>OD9UJdv@&-s&)I_vA`Re6A>w<@&z*u{^U zNM>Y|=|Eaw?sGwbQz8wZm{Eps;>+Zhl;)y&bt}^DOw#I^{)aN$DLXdP!`L0f`XAr@ zNzuo4htg$9DeSr8F2`-vH1j&+?Z>S5BU z1{W9dH6=+(a7Y3(bKFRQ6ez9x`>1i0<+E&5z~F|_r4=(`F;Z&_{42Ai>K4mJ#`y#k z6;w`T)q3}a`k5+!Wf+k;=AZ?$94>f*>*F2}6Gz*s@S>r|;uiK3;MP4eGt7 z>&?^BiBQgE{q+w+zqz5?o0jPZD~IF;ls5;=uwiDt{S!p2EM(wGA3?HuTr$IW4xUwU zT{8huufOpckMA(ey?WVr_p1OL(IdjNPywP;%>5J%)pIXh__k{no1mZfr1Tvf94}bs zM@#nlSjug3$}SXTMvu1|C)Jwcdg64fK!dxYZ$`gOi5usUU271@)Vt3b$maPE)T3TX zMbg17{TV&;l`Ty_97KOBmlqU`igvhDY)rUlTYpEx^qTpD-N%<=Y1Qia?)WuIw93=$ zzWPdO`_hQ~cPZ_K9Ig}@Wi=g%_a51VJ0tf$i0$x9@W(BxHDBf6gp-m)Mu$tdL z2g4H*nxsxO7MutK&RF*#rt^z^P6;E`KUp%-*D`4Uyo9Lb`%T|{;F{pv>#!W-Z01~N zk`KF3id>zSU%f0_Cit=-QM2Y^do0g8Z$DBg*K(tpUKR}7+xtU&_Hi|5AzLUoiIzSi zTNDx#@uhR`gE-bN$6>>U>U;Y})rZff`@3N$!rqUW53=Fi9K0kQA8bu2{v1yTsMaGiEP zYxH4q03v?AXV8?oXr<^9*to~`-TtUdPhSn6?kHLo_>CPMb4a01*VE$o+0K+Kd=o<0 z|FWU_OcYqbJUwT3Ehe_Cn#NQ1>@0zP&ygy$_dAO2OaWc!pdRPf!u!2SGG)MXFPrv} zQ=nzEjcu~diazI(bF+drI(u-Y*(9WZ7LF;igt@HZ1qKs^Z+^r^7628P&RPCrCK;9) zPXRUsBrsa8UW#Zj#QmGs*RA)ipM7-1FM}Wzke{1KbKpJZCdsM{jvDUInEUvh#dbb~ z3WAmbk4@_n%UB{*W4%yX_3|z3+ve^x|G2Ns=1#Yl)l|At> zWX{Lwc{RSvfRhCvp&%2~@nl(pBs+MbjqhR`onap^2Q1IT*mCGM`7%zJ&?7mgcj986Ylp&uUf=nuP_wT>Pzg^=YWO%ZEUv-D&&L|(y=_4JQIo+1b7}E)Z!*(wKRVxV z?)9gjI_u~}k#e^QRp(Br#WN05hi|%i_HmkJpmu2hnQR{ixCx|7FQ($_HCpK?`^*;6 z*Fn0S_o|9z<~x6Q6W4tw+737wO>OPjnt`LqkN*g@1(%SRYa8vTNM& zK#8cp_oQs5fw?7n9QCA{Wr@UW4jlBCdHu44k0e z*a0VKE-W)9EH4$hk6Kx9%hgp;#mjKbs^k4Wis2MZbqs=rEHwrSkz5Ax?{uh6!@C!>!UlX@g zEx4fPmm_+UkZOw-^n1a`FLD!>EXa`Vm;ov*_HGKpEY1sx9_5ZkFuYBue8}A5Di|_a zM*KDcZTj1P)FGb_QaP-z+IB)GU%+|iIvNRPCai~uB}~kETt@y@?+WC*(0>%dU{R+P z7fyVl$Ril1LbQhvtB8u>^sX3uG~j@!Ga}tkqL*1s#lN+Y!>jnn)7;|Rqdg<~Z64Yv z*S{1ahq)vWmi+Zl;p(!iUE%Oe*eySSa?Kn(juPa0G>eS3Z|a{%Uw11;YGzy3RE2Mv z#8U{!mMG~rs>8RG8ufDdyiq#Xzvqd+ku!Y0)S);20o;l~{-BS-hp^&{E#8g_kenxW zC#d@BSvZ=;9Ry5ipKa7q`%ckChUE6YI!4q(d1SBV;@yD!oZ0bfwTIuBPPxGv zNa4I=fI&?41YPzPY>!54JivzlJ2aq0;lB*@4i<3tfdVxT`xHeqB`^oN)VK^vI!Ic| zjo5^Ngd84fmf-ozVIMX3cPK;n@K5a!?S_JTmjEa~s>j9Zhko=A=IEtbJ~394gCmM) z6@U|Tr}Pt%r>xmbhpbeu8 z>xc6ik3_x@rA0h{o_-q>Px6j$${y~LcW=m^H}Ir^JCDZWl~co$Vy8!1O=;H4M~8Hu z$pNS-|KkGKFoPQMv5Q&hd>7%F{(_Yr;ex+wd*+!epPVA`f%C zpI^7t&UxAlA|l{a1S8av*M;IY)FgE;&o2cKg zrJ=N|N`t@7FNp7D^U(SKT3)0OI$xi%v5HdtO0)Cr6$=;I{3paYIL46`&2Uyu zbN79hB|Y+&gc6f|3wg(DvpWz1m4docE|FWYdcbpX$;0$HntDN3I)r#VK{t*}{4;B* zr%x`E*c=cCmBB)_cI+kbqQ(CPvVK5fz;crFiFoH&NH_BTsQ%~8*s51;hpEzT(S7x- zo%6st0ik4Qb-XRwo?c1BdSDeU@9EN+rBVm;n~!*bR^s$PEJ+M;3+4y?gJ$WO8?23ld5TaY7DKWWz{(up2SHY7YF`y}1?;x#1kM0mm;%qg zU?}4}pe$Jr!R(wOs!z<)pCmMy2U&v`E{5OHdvJDB*cnFQqM>!SZWMmawna36ZYaa& zQ0rbke`J~8CU;^o Date: Fri, 4 Nov 2016 20:58:35 -0500 Subject: [PATCH 04/11] Moved files around --- Cely.xcodeproj/project.pbxproj | 16 +++++--- Cely/Cely.swift | 3 +- Cely/CelyProtocols.swift | 2 +- Cely/{ => Supporting Files}/Cely.storyboard | 0 .../CelyLoginViewController.swift | 41 ------------------- Cely/{ => Supporting Files}/Info.plist | 0 CelyTests/LoginStyleTests.swift | 2 +- 7 files changed, 14 insertions(+), 50 deletions(-) rename Cely/{ => Supporting Files}/Cely.storyboard (100%) rename Cely/{ => Supporting Files}/CelyLoginViewController.swift (66%) rename Cely/{ => Supporting Files}/Info.plist (100%) diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index c2410d0..a113fd0 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 31358EC51DB31D3300AC7119 /* Locksmith.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31358EC41DB31D3300AC7119 /* Locksmith.framework */; }; 31358EC61DB31D3300AC7119 /* Locksmith.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 31358EC41DB31D3300AC7119 /* Locksmith.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 317516421DB7BD9D00974002 /* TestStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 317516401DB7B23C00974002 /* TestStoryboard.storyboard */; }; + 31D9B96C1DCD72700039BCB8 /* CelyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */; }; 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */; }; /* End PBXBuildFile section */ @@ -93,13 +94,13 @@ 1F9E55C21DC2426000435B52 /* LoginViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewControllerTests.swift; sourceTree = ""; }; 1FAA023C1D4E7B5B00A6D209 /* Cely.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cely.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1FAA023F1D4E7B5B00A6D209 /* Cely.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Cely.h; sourceTree = ""; }; - 1FAA02411D4E7B5B00A6D209 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1FAA02411D4E7B5B00A6D209 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Supporting Files/Info.plist"; sourceTree = ""; }; 1FABFAEC1DBE727F0096DD36 /* TestMain.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = TestMain.storyboard; path = CelyTests/TestMain.storyboard; sourceTree = SOURCE_ROOT; }; 1FB2B23C1DB1751600716E80 /* CelyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CelyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1FB2B23E1DB1751600716E80 /* CelyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CelyTests.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FB2B2401DB1751600716E80 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1FDAB4D91D4E7BC9003AC5EE /* Cely.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Cely.storyboard; sourceTree = ""; }; - 1FDAB4DB1D4E7BDC003AC5EE /* CelyLoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyLoginViewController.swift; sourceTree = ""; }; + 1FDAB4D91D4E7BC9003AC5EE /* Cely.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Cely.storyboard; path = "Supporting Files/Cely.storyboard"; sourceTree = ""; }; + 1FDAB4DB1D4E7BDC003AC5EE /* CelyLoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CelyLoginViewController.swift; path = "Supporting Files/CelyLoginViewController.swift"; sourceTree = ""; }; 1FDAB4DD1D4E7BE4003AC5EE /* Cely.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Cely.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 311B1F2B1DB31FF6005A155B /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 311B1F2D1DB3230F005A155B /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; @@ -115,6 +116,7 @@ 31358EBF1DB31CA800AC7119 /* Locksmith.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Locksmith.framework; sourceTree = ""; }; 31358EC41DB31D3300AC7119 /* Locksmith.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Locksmith.framework; path = "Cely Demo/Locksmith.framework"; sourceTree = ""; }; 317516401DB7B23C00974002 /* TestStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = TestStoryboard.storyboard; path = ../CelyTests/Frameworks/TestStoryboard.storyboard; sourceTree = ""; }; + 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyProtocols.swift; sourceTree = ""; }; 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyWindowManagerTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -186,6 +188,7 @@ 1FB2B23D1DB1751600716E80 /* CelyTests */ = { isa = PBXGroup; children = ( + 1FABFAEC1DBE727F0096DD36 /* TestMain.storyboard */, 1FB2B23E1DB1751600716E80 /* CelyTests.swift */, 1F9E55C21DC2426000435B52 /* LoginViewControllerTests.swift */, 1F0C13341DB188AB00AC1C94 /* CelyStorageTests.swift */, @@ -198,9 +201,9 @@ 1FB2B24A1DB1754B00716E80 /* Supporting Files */ = { isa = PBXGroup; children = ( + 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */, 1FAA02411D4E7B5B00A6D209 /* Info.plist */, 1FDAB4D91D4E7BC9003AC5EE /* Cely.storyboard */, - 1FABFAEC1DBE727F0096DD36 /* TestMain.storyboard */, 1FDAB4DB1D4E7BDC003AC5EE /* CelyLoginViewController.swift */, ); name = "Supporting Files"; @@ -409,6 +412,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31D9B96C1DCD72700039BCB8 /* CelyProtocols.swift in Sources */, 1F801A201DB143C100187FA6 /* CelyConstants.swift in Sources */, 1FDAB4DE1D4E7BE4003AC5EE /* Cely.swift in Sources */, 1FDAB4DC1D4E7BDC003AC5EE /* CelyLoginViewController.swift in Sources */, @@ -591,7 +595,7 @@ "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Cely\\ Demo", ); - INFOPLIST_FILE = Cely/Info.plist; + INFOPLIST_FILE = "$(SRCROOT)/Cely/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.chaione.Cely; @@ -618,7 +622,7 @@ "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Cely\\ Demo", ); - INFOPLIST_FILE = Cely/Info.plist; + INFOPLIST_FILE = "$(SRCROOT)/Cely/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.chaione.Cely; diff --git a/Cely/Cely.swift b/Cely/Cely.swift index 5cdaefc..e4a5caa 100644 --- a/Cely/Cely.swift +++ b/Cely/Cely.swift @@ -80,7 +80,8 @@ extension Cely { /// - parameter value: data you want to save /// - parameter key: String for the key /// - parameter store: Storage `Cely` will be using. Defaulted to `Storage` - /// - parameter persisted: `Boolean`: Keep data after logout + /// - parameter secure: `Boolean`: Store data securely + /// - parameter persist: `Boolean`: Keep data after logout /// /// - returns: `Boolean`: Whether or not your value was successfully set. @discardableResult public static func save(_ value: Any?, forKey key: String, toStorage store: CelyStorageProtocol = store, securely secure: Bool = false, persisted persist: Bool = false) -> StorageResult { diff --git a/Cely/CelyProtocols.swift b/Cely/CelyProtocols.swift index 449b088..b38b85f 100644 --- a/Cely/CelyProtocols.swift +++ b/Cely/CelyProtocols.swift @@ -16,7 +16,7 @@ public protocol CelyUser { /// Protocol a storage class must abide by in order for Cely to use it public protocol CelyStorageProtocol { - func set(_ value: Any?, forKey key: String, securely secure: Bool) -> StorageResult + func set(_ value: Any?, forKey key: String, securely secure: Bool, persisted persist: Bool) -> StorageResult func get(_ key: String) -> Any? func removeAllData() } diff --git a/Cely/Cely.storyboard b/Cely/Supporting Files/Cely.storyboard similarity index 100% rename from Cely/Cely.storyboard rename to Cely/Supporting Files/Cely.storyboard diff --git a/Cely/CelyLoginViewController.swift b/Cely/Supporting Files/CelyLoginViewController.swift similarity index 66% rename from Cely/CelyLoginViewController.swift rename to Cely/Supporting Files/CelyLoginViewController.swift index 841a574..0cb2e62 100644 --- a/Cely/CelyLoginViewController.swift +++ b/Cely/Supporting Files/CelyLoginViewController.swift @@ -91,47 +91,6 @@ internal extension CelyLoginViewController { } } -internal extension CelyLoginViewController { - - func keyboardWillShowNotification(notification: NSNotification) { - updateBottomLayoutConstraintWithNotification(notification: notification) - } - - func keyboardWillHideNotification(notification: NSNotification) { - updateBottomLayoutConstraintWithNotification(notification: notification) - } - - // MARK: - Private - - fileprivate func setUpKeyboardNotification() { - NotificationCenter.default - .addObserver(self, selector: #selector(keyboardWillShowNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil) - NotificationCenter.default - .addObserver(self, selector: #selector(keyboardWillHideNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil) - } - - fileprivate func updateBottomLayoutConstraintWithNotification(notification: NSNotification) { - let userInfo = notification.userInfo! - - guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, - let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue, - let rawCurve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as? NSNumber else { return } - - let animationDuration = (duration).doubleValue - let keyboardEndFrame = (endFrame).cgRectValue - let convertedKeyboardEndFrame = view.convert(keyboardEndFrame, from: view.window) - let rawAnimationCurve = (rawCurve).uint32Value << 16 - let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) - - let newConstraint = view.bounds.maxY - convertedKeyboardEndFrame.minY - bottomLayoutConstraint.constant = newConstraint == 0 ? 206 : newConstraint - - UIView.animate(withDuration: animationDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { - self.view.layoutIfNeeded() - }, completion: nil) - } -} - extension CelyLoginViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { diff --git a/Cely/Info.plist b/Cely/Supporting Files/Info.plist similarity index 100% rename from Cely/Info.plist rename to Cely/Supporting Files/Info.plist diff --git a/CelyTests/LoginStyleTests.swift b/CelyTests/LoginStyleTests.swift index 079b088..bbb29ef 100644 --- a/CelyTests/LoginStyleTests.swift +++ b/CelyTests/LoginStyleTests.swift @@ -12,7 +12,7 @@ class LoginStyleTests: XCTestCase { override func setUp() { super.setUp() - + } override func tearDown() { From 9974588733e1cb1265e9d9216dc29d1a13004c62 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Fri, 4 Nov 2016 22:03:28 -0500 Subject: [PATCH 05/11] Add style to storyboard --- Cely.xcodeproj/project.pbxproj | 8 +- Cely/Supporting Files/Cely.storyboard | 89 ++++++++++++------- .../CelyLoginViewController.swift | 33 +++---- 3 files changed, 75 insertions(+), 55 deletions(-) diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index a113fd0..a5c46fe 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 31358EC61DB31D3300AC7119 /* Locksmith.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 31358EC41DB31D3300AC7119 /* Locksmith.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 317516421DB7BD9D00974002 /* TestStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 317516401DB7B23C00974002 /* TestStoryboard.storyboard */; }; 31D9B96C1DCD72700039BCB8 /* CelyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */; }; + 31D9B96E1DCD748F0039BCB8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */; }; 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */; }; /* End PBXBuildFile section */ @@ -117,6 +118,7 @@ 31358EC41DB31D3300AC7119 /* Locksmith.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Locksmith.framework; path = "Cely Demo/Locksmith.framework"; sourceTree = ""; }; 317516401DB7B23C00974002 /* TestStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = TestStoryboard.storyboard; path = ../CelyTests/Frameworks/TestStoryboard.storyboard; sourceTree = ""; }; 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyProtocols.swift; sourceTree = ""; }; + 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "Supporting Files/Assets.xcassets"; sourceTree = ""; }; 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyWindowManagerTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -174,11 +176,12 @@ 1FAA023E1D4E7B5B00A6D209 /* Cely */ = { isa = PBXGroup; children = ( + 1FAA023F1D4E7B5B00A6D209 /* Cely.h */, 1FDAB4DD1D4E7BE4003AC5EE /* Cely.swift */, 1F801A1F1DB143C100187FA6 /* CelyConstants.swift */, + 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */, 1F801A211DB1473A00187FA6 /* CelyStorage.swift */, 1F801A1A1DB141C100187FA6 /* CelyWindowManager.swift */, - 1FAA023F1D4E7B5B00A6D209 /* Cely.h */, 1FB2B24A1DB1754B00716E80 /* Supporting Files */, 1FAA023D1D4E7B5B00A6D209 /* Products */, ); @@ -201,7 +204,7 @@ 1FB2B24A1DB1754B00716E80 /* Supporting Files */ = { isa = PBXGroup; children = ( - 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */, + 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */, 1FAA02411D4E7B5B00A6D209 /* Info.plist */, 1FDAB4D91D4E7BC9003AC5EE /* Cely.storyboard */, 1FDAB4DB1D4E7BDC003AC5EE /* CelyLoginViewController.swift */, @@ -366,6 +369,7 @@ buildActionMask = 2147483647; files = ( 1FDAB4DA1D4E7BC9003AC5EE /* Cely.storyboard in Resources */, + 31D9B96E1DCD748F0039BCB8 /* Assets.xcassets in Resources */, 1FABFAED1DBE727F0096DD36 /* TestMain.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Cely/Supporting Files/Cely.storyboard b/Cely/Supporting Files/Cely.storyboard index f1fca64..27dd56d 100644 --- a/Cely/Supporting Files/Cely.storyboard +++ b/Cely/Supporting Files/Cely.storyboard @@ -4,6 +4,7 @@ + @@ -19,48 +20,70 @@ - - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + - + diff --git a/Cely/Supporting Files/CelyLoginViewController.swift b/Cely/Supporting Files/CelyLoginViewController.swift index 0cb2e62..543e254 100644 --- a/Cely/Supporting Files/CelyLoginViewController.swift +++ b/Cely/Supporting Files/CelyLoginViewController.swift @@ -18,7 +18,7 @@ class CelyLoginViewController: UIViewController { @IBOutlet fileprivate weak var bottomLayoutConstraint: NSLayoutConstraint! // MARK: - Variables - + var initialBottomConstant: CGFloat! // MARK: - ViewController Life Cycle override func viewDidLoad() { @@ -29,15 +29,15 @@ class CelyLoginViewController: UIViewController { loginButton?.addTarget(self, action: #selector(didPressLogin), for: .touchUpInside) } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) setUpKeyboardNotification() + initialBottomConstant = bottomLayoutConstraint.constant } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) + NotificationCenter.default.removeObserver(self) } func didPressLogin() { @@ -52,24 +52,14 @@ class CelyLoginViewController: UIViewController { internal extension CelyLoginViewController { - func keyboardWillShowNotification(notification: NSNotification) { - updateBottomLayoutConstraintWithNotification(notification: notification) - } - - func keyboardWillHideNotification(notification: NSNotification) { - updateBottomLayoutConstraintWithNotification(notification: notification) - } - // MARK: - Private fileprivate func setUpKeyboardNotification() { - NotificationCenter.default - .addObserver(self, selector: #selector(keyboardWillShowNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil) - NotificationCenter.default - .addObserver(self, selector: #selector(keyboardWillHideNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardNotification(notification:)), + name: .UIKeyboardWillChangeFrame, object: nil) } - fileprivate func updateBottomLayoutConstraintWithNotification(notification: NSNotification) { + func keyboardNotification(notification: NSNotification) { let userInfo = notification.userInfo! guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, @@ -83,9 +73,12 @@ internal extension CelyLoginViewController { let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) let newConstraint = view.bounds.maxY - convertedKeyboardEndFrame.minY - bottomLayoutConstraint.constant = newConstraint == 0 ? 206 : newConstraint + bottomLayoutConstraint.constant = newConstraint == 0 ? initialBottomConstant : newConstraint - UIView.animate(withDuration: animationDuration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { + UIView.animate(withDuration: animationDuration, + delay: 0.0, + options: [.beginFromCurrentState, animationCurve], + animations: { self.view.layoutIfNeeded() }, completion: nil) } From 3eee80029ac32da86bf2f94010b50a24d6c0e841 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Fri, 4 Nov 2016 23:46:07 -0500 Subject: [PATCH 06/11] finish CelyStyles need to clean up code and do documentation --- Cely Demo/AppDelegate.swift | 1 + .../511993.png | Bin .../Contents.json | 0 Cely Demo/LoginStyles.swift | 25 +++++++++++++ Cely.xcodeproj/project.pbxproj | 18 ++++++++-- Cely/CelyProtocols.swift | 33 +++++++++++++++++- Cely/CelyWindowManager.swift | 4 +++ .../{CelyThin.png => CelyLogo.png} | Bin .../{CelyThin@2x.png => CelyLogo@2x.png} | Bin .../CelyLogo.imageset/Contents.json | 4 +-- .../ChaiOneLogo.png} | Bin .../Contents.json | 2 +- Cely/Supporting Files/Cely.storyboard | 1 + .../CelyLoginViewController.swift | 17 +++++++++ 14 files changed, 98 insertions(+), 7 deletions(-) rename Cely Demo/Assets.xcassets/{ChaiOne Logo.imageset => ChaiOneLogo.imageset}/511993.png (100%) rename Cely Demo/Assets.xcassets/{ChaiOne Logo.imageset => ChaiOneLogo.imageset}/Contents.json (100%) create mode 100644 Cely Demo/LoginStyles.swift rename Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/{CelyThin.png => CelyLogo.png} (100%) rename Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/{CelyThin@2x.png => CelyLogo@2x.png} (100%) rename Cely/Supporting Files/Assets.xcassets/{ChaiOne Logo.imageset/511993.png => ChaiOneLogo.imageset/ChaiOneLogo.png} (100%) rename Cely/Supporting Files/Assets.xcassets/{ChaiOne Logo.imageset => ChaiOneLogo.imageset}/Contents.json (87%) diff --git a/Cely Demo/AppDelegate.swift b/Cely Demo/AppDelegate.swift index ab61b00..f6a33d9 100644 --- a/Cely Demo/AppDelegate.swift +++ b/Cely Demo/AppDelegate.swift @@ -18,6 +18,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.Token], withOptions: [ + .LoginStyle: LoginStyles(), .LoginCompletionBlock: { (username: String, password: String) in if username == "asdf" && password == "asdf" { Cely.save(username, forKey: "username", persisted: true) diff --git a/Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/511993.png b/Cely Demo/Assets.xcassets/ChaiOneLogo.imageset/511993.png similarity index 100% rename from Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/511993.png rename to Cely Demo/Assets.xcassets/ChaiOneLogo.imageset/511993.png diff --git a/Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/Contents.json b/Cely Demo/Assets.xcassets/ChaiOneLogo.imageset/Contents.json similarity index 100% rename from Cely Demo/Assets.xcassets/ChaiOne Logo.imageset/Contents.json rename to Cely Demo/Assets.xcassets/ChaiOneLogo.imageset/Contents.json diff --git a/Cely Demo/LoginStyles.swift b/Cely Demo/LoginStyles.swift new file mode 100644 index 0000000..1f40f36 --- /dev/null +++ b/Cely Demo/LoginStyles.swift @@ -0,0 +1,25 @@ +// +// LoginStyles.swift +// Cely +// +// Created by Fabian Buentello on 11/4/16. +// Copyright © 2016 Fabian Buentello. All rights reserved. +// + +import Foundation +import Cely + +struct LoginStyles: CelyStyle { + + func backgroundColor() -> UIColor { + return .red + } + + func textFieldBackgroundColor() -> UIColor { + return .blue + } + + func appLogo() -> UIImage? { + return UIImage(named: "ChaiOneLogo") + } +} diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index a5c46fe..e4d198f 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 317516421DB7BD9D00974002 /* TestStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 317516401DB7B23C00974002 /* TestStoryboard.storyboard */; }; 31D9B96C1DCD72700039BCB8 /* CelyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */; }; 31D9B96E1DCD748F0039BCB8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */; }; + 31DA8A581DCD8E8F0006C598 /* LoginStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */; }; 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */; }; /* End PBXBuildFile section */ @@ -119,6 +120,7 @@ 317516401DB7B23C00974002 /* TestStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = TestStoryboard.storyboard; path = ../CelyTests/Frameworks/TestStoryboard.storyboard; sourceTree = ""; }; 31D9B96B1DCD72700039BCB8 /* CelyProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyProtocols.swift; sourceTree = ""; }; 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "Supporting Files/Assets.xcassets"; sourceTree = ""; }; + 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginStyles.swift; sourceTree = ""; }; 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyWindowManagerTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -224,18 +226,27 @@ isa = PBXGroup; children = ( 31358EBF1DB31CA800AC7119 /* Locksmith.framework */, - 31358EB91DB31BDE00AC7119 /* Cely Demo.entitlements */, 31358EA91DB31BC400AC7119 /* AppDelegate.swift */, 31358EAB1DB31BC400AC7119 /* ViewController.swift */, + 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */, 311B1F2D1DB3230F005A155B /* SettingsViewController.swift */, + 31DA8A561DCD8E600006C598 /* Supporting Files */, + 311B1F2B1DB31FF6005A155B /* User.swift */, + ); + path = "Cely Demo"; + sourceTree = ""; + }; + 31DA8A561DCD8E600006C598 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 31358EB91DB31BDE00AC7119 /* Cely Demo.entitlements */, 31358EAD1DB31BC400AC7119 /* Main.storyboard */, 317516401DB7B23C00974002 /* TestStoryboard.storyboard */, 31358EB01DB31BC400AC7119 /* Assets.xcassets */, 31358EB21DB31BC400AC7119 /* LaunchScreen.storyboard */, 31358EB51DB31BC400AC7119 /* Info.plist */, - 311B1F2B1DB31FF6005A155B /* User.swift */, ); - path = "Cely Demo"; + name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ @@ -442,6 +453,7 @@ files = ( 31358EAC1DB31BC400AC7119 /* ViewController.swift in Sources */, 31358EAA1DB31BC400AC7119 /* AppDelegate.swift in Sources */, + 31DA8A581DCD8E8F0006C598 /* LoginStyles.swift in Sources */, 311B1F2C1DB31FF6005A155B /* User.swift in Sources */, 311B1F2E1DB3230F005A155B /* SettingsViewController.swift in Sources */, ); diff --git a/Cely/CelyProtocols.swift b/Cely/CelyProtocols.swift index b38b85f..0712a0a 100644 --- a/Cely/CelyProtocols.swift +++ b/Cely/CelyProtocols.swift @@ -21,4 +21,35 @@ public protocol CelyStorageProtocol { func removeAllData() } -public protocol CelyStyle {} +public protocol CelyStyle { + func backgroundColor() -> UIColor + func textFieldBackgroundColor() -> UIColor + func buttonBackgroundColor() -> UIColor + func buttonTextColor() -> UIColor + func appLogo() -> UIImage? +} + +public extension CelyStyle { + + func backgroundColor() -> UIColor { + return .white + } + + func textFieldBackgroundColor() -> UIColor { + return .white + } + + func buttonBackgroundColor() -> UIColor { + return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) + } + + func buttonTextColor() -> UIColor { + return .white + } + + func appLogo() -> UIImage? { + return UIImage(named: "CelyLogo") + } +} + +struct DefaultSyle: CelyStyle {} diff --git a/Cely/CelyWindowManager.swift b/Cely/CelyWindowManager.swift index 6dbfde3..b5adc25 100644 --- a/Cely/CelyWindowManager.swift +++ b/Cely/CelyWindowManager.swift @@ -16,6 +16,7 @@ public class CelyWindowManager { public var loginStoryboard: UIStoryboard! public var homeStoryboard: UIStoryboard! + public var loginStyle: CelyStyle! private init() { let notTesting = ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil @@ -29,6 +30,9 @@ public class CelyWindowManager { static func setup(window _window: UIWindow, withOptions options: [CelyOptions : Any?]? = [:]) { CelyWindowManager.manager.window = _window + // Set the login Styles + CelyWindowManager.manager.loginStyle = options?[.LoginStyle] as? CelyStyle ?? DefaultSyle() + // Set the HomeStoryboard CelyWindowManager.setHomeStoryboard(options?[.HomeStoryboard] as? UIStoryboard) diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin.png b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyLogo.png similarity index 100% rename from Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin.png rename to Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyLogo.png diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin@2x.png b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyLogo@2x.png similarity index 100% rename from Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyThin@2x.png rename to Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/CelyLogo@2x.png diff --git a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json index 9af9c85..89a0938 100644 --- a/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json +++ b/Cely/Supporting Files/Assets.xcassets/CelyLogo.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "CelyThin.png", + "filename" : "CelyLogo.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "CelyThin@2x.png", + "filename" : "CelyLogo@2x.png", "scale" : "2x" }, { diff --git a/Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/511993.png b/Cely/Supporting Files/Assets.xcassets/ChaiOneLogo.imageset/ChaiOneLogo.png similarity index 100% rename from Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/511993.png rename to Cely/Supporting Files/Assets.xcassets/ChaiOneLogo.imageset/ChaiOneLogo.png diff --git a/Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/Contents.json b/Cely/Supporting Files/Assets.xcassets/ChaiOneLogo.imageset/Contents.json similarity index 87% rename from Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/Contents.json rename to Cely/Supporting Files/Assets.xcassets/ChaiOneLogo.imageset/Contents.json index d4027c8..80f34e4 100644 --- a/Cely/Supporting Files/Assets.xcassets/ChaiOne Logo.imageset/Contents.json +++ b/Cely/Supporting Files/Assets.xcassets/ChaiOneLogo.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "511993.png", + "filename" : "ChaiOneLogo.png", "scale" : "1x" }, { diff --git a/Cely/Supporting Files/Cely.storyboard b/Cely/Supporting Files/Cely.storyboard index 27dd56d..347d166 100644 --- a/Cely/Supporting Files/Cely.storyboard +++ b/Cely/Supporting Files/Cely.storyboard @@ -83,6 +83,7 @@ + diff --git a/Cely/Supporting Files/CelyLoginViewController.swift b/Cely/Supporting Files/CelyLoginViewController.swift index 543e254..fe385fd 100644 --- a/Cely/Supporting Files/CelyLoginViewController.swift +++ b/Cely/Supporting Files/CelyLoginViewController.swift @@ -11,6 +11,8 @@ import UIKit class CelyLoginViewController: UIViewController { // MARK: - IBOutlets + + @IBOutlet weak var appImageView: UIImageView! @IBOutlet weak var usernameField: UITextField? @IBOutlet weak var passwordField: UITextField? @IBOutlet weak var loginButton: UIButton? @@ -19,6 +21,7 @@ class CelyLoginViewController: UIViewController { // MARK: - Variables var initialBottomConstant: CGFloat! + var styles: CelyStyle! // MARK: - ViewController Life Cycle override func viewDidLoad() { @@ -26,9 +29,23 @@ class CelyLoginViewController: UIViewController { usernameField?.delegate = self passwordField?.delegate = self + setupStyle() loginButton?.addTarget(self, action: #selector(didPressLogin), for: .touchUpInside) } + private func setupStyle() { + + styles = CelyWindowManager.manager.loginStyle + + view.backgroundColor = styles.backgroundColor() + loginButton?.setTitleColor(styles.buttonTextColor(), for: .normal) + loginButton?.backgroundColor = styles.buttonBackgroundColor() + textFields?.forEach({$0.backgroundColor = styles.textFieldBackgroundColor()}) + if let image = styles.appLogo() { + appImageView.image = image + } + } + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) setUpKeyboardNotification() From 0b1814850e1c8c2214367e4bd0a2f48849a4c900 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Sat, 5 Nov 2016 07:22:30 -0500 Subject: [PATCH 07/11] swift 3 enums --- .swiftlint.yml | 1 + Cely Demo/AppDelegate.swift | 6 ++-- Cely/Cely.swift | 14 +++++----- Cely/CelyConstants.swift | 22 +++++++-------- Cely/CelyStorage.swift | 12 ++++---- Cely/CelyWindowManager.swift | 12 ++++---- CelyTests/CelyStorageTests.swift | 4 +-- CelyTests/CelyTests.swift | 40 +++++++++++++-------------- CelyTests/CelyWindowManagerTest.swift | 8 +++--- 9 files changed, 60 insertions(+), 59 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index a862021..06a353f 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -2,6 +2,7 @@ disabled_rules: # rule identifiers to exclude from running - line_length - variable_name - force_cast + - type_name opt_in_rules: - missing-docs diff --git a/Cely Demo/AppDelegate.swift b/Cely Demo/AppDelegate.swift index f6a33d9..8e2c3f0 100644 --- a/Cely Demo/AppDelegate.swift +++ b/Cely Demo/AppDelegate.swift @@ -18,12 +18,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.Token], withOptions: [ - .LoginStyle: LoginStyles(), - .LoginCompletionBlock: { (username: String, password: String) in + .loginStyle: LoginStyles(), + .loginCompletionBlock: { (username: String, password: String) in if username == "asdf" && password == "asdf" { Cely.save(username, forKey: "username", persisted: true) Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true) - Cely.changeStatus(to: .LoggedIn) + Cely.changeStatus(to: .loggedIn) } } ]) diff --git a/Cely/Cely.swift b/Cely/Cely.swift index e4a5caa..a921efc 100644 --- a/Cely/Cely.swift +++ b/Cely/Cely.swift @@ -33,8 +33,8 @@ public struct Cely { Cely.requiredProperties = requiredProperties.flatMap({"\($0.rawValue)"}) - Cely.loginCompletionBlock = options?[.LoginCompletionBlock] as? CelyLoginCompletion - store = options?[.Storage] as? CelyStorageProtocol ?? store + Cely.loginCompletionBlock = options?[.loginCompletionBlock] as? CelyLoginCompletion + store = options?[.storage] as? CelyStorageProtocol ?? store if let window = window { CelyWindowManager.setup(window: window, withOptions: options) @@ -52,16 +52,16 @@ extension Cely { /// /// - returns: `CelyStatus`. If `requiredProperties` are all in store, it will return `.LoggedIn`, else `.LoggedOut` public static func currentLoginStatus(requiredProperties properties: [CelyProperty] = requiredProperties, fromStorage store: CelyStorageProtocol = store) -> CelyStatus { - guard properties.count > 0 else { return .LoggedOut } + guard properties.count > 0 else { return .loggedOut } let missingRequiredProperties = properties .map({return store.get($0)}) .contains(where: {$0 == nil}) if missingRequiredProperties { - return .LoggedOut + return .loggedOut } else { - return .LoggedIn + return .loggedIn } } @@ -100,13 +100,13 @@ extension Cely { /// - parameter store: Storage `Cely` will be using. Defaulted to `CelyStorageProtocol` public static func logout(useStorage store: CelyStorageProtocol = store) { store.removeAllData() - changeStatus(to: .LoggedOut) + changeStatus(to: .loggedOut) } /// Returns whether or not the user is logged in /// /// - returns: `Boolean` public static func isLoggedIn() -> Bool { - return currentLoginStatus() == .LoggedIn + return currentLoginStatus() == .loggedIn } } diff --git a/Cely/CelyConstants.swift b/Cely/CelyConstants.swift index 4b318a9..e4d7a4a 100644 --- a/Cely/CelyConstants.swift +++ b/Cely/CelyConstants.swift @@ -17,31 +17,31 @@ public typealias CelyCommands = String /// Statuses for Cely to perform actions on public enum CelyStatus: CelyCommands { - case LoggedIn = "CelyStatus.LoggedIn.user" - case LoggedOut = "CelyStatus.LoggedOut.user" + case loggedIn = "CelyStatus.loggedIn.user" + case loggedOut = "CelyStatus.loggedOut.user" } /// Options that you can pass into Cely on `Cely.setup(_:)` public enum CelyOptions { - case Storage - case HomeStoryboard - case LoginStoryboard - case LoginCompletionBlock - case LoginStyle + case storage + case homeStoryboard + case loginStoryboard + case loginCompletionBlock + case loginStyle } // enum result on whether or not Cely successfully saved your data public enum StorageResult: Equatable { - case Success - case Fail(LocksmithError) + case success + case fail(LocksmithError) } public func == (lhs: StorageResult, rhs: StorageResult) -> Bool { switch (lhs, rhs) { - case (let .Fail(error1), let .Fail(error2)): + case (let .fail(error1), let .fail(error2)): return error1 == error2 - case (.Success, .Success): + case (.success, .success): return true default: diff --git a/Cely/CelyStorage.swift b/Cely/CelyStorage.swift index de5642a..7345459 100644 --- a/Cely/CelyStorage.swift +++ b/Cely/CelyStorage.swift @@ -80,7 +80,7 @@ public class CelyStorage: CelyStorageProtocol { /// /// - returns: `Boolean` on whether or not it successfully saved public func set(_ value: Any?, forKey key: String, securely secure: Bool = false, persisted: Bool = false) -> StorageResult { - guard let val = value else { return .Fail(.undefined) } + guard let val = value else { return .fail(.undefined) } if secure { var currentStorage = CelyStorage.sharedInstance.secureStorage currentStorage[key] = val @@ -89,15 +89,15 @@ public class CelyStorage: CelyStorageProtocol { // If testing, user `saveData` instead of `updateData` if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil { try Locksmith.saveData(data: currentStorage, forUserAccount: kCelyLocksmithAccount, inService: kCelyLocksmithService) - return .Success + return .success } try Locksmith.updateData(data: currentStorage, forUserAccount: kCelyLocksmithAccount, inService: kCelyLocksmithService) - return .Success + return .success } catch let storageError as LocksmithError { - return .Fail(storageError) + return .fail(storageError) } catch { - return .Fail(.undefined) + return .fail(.undefined) } } else { if persisted { @@ -110,7 +110,7 @@ public class CelyStorage: CelyStorageProtocol { UserDefaults.standard.setPersistentDomain(CelyStorage.sharedInstance.storage, forName: kCelyDomain) UserDefaults.standard.synchronize() } - return .Success + return .success } /// Retrieve user data from key diff --git a/Cely/CelyWindowManager.swift b/Cely/CelyWindowManager.swift index b5adc25..c6b391d 100644 --- a/Cely/CelyWindowManager.swift +++ b/Cely/CelyWindowManager.swift @@ -31,16 +31,16 @@ public class CelyWindowManager { CelyWindowManager.manager.window = _window // Set the login Styles - CelyWindowManager.manager.loginStyle = options?[.LoginStyle] as? CelyStyle ?? DefaultSyle() + CelyWindowManager.manager.loginStyle = options?[.loginStyle] as? CelyStyle ?? DefaultSyle() // Set the HomeStoryboard - CelyWindowManager.setHomeStoryboard(options?[.HomeStoryboard] as? UIStoryboard) + CelyWindowManager.setHomeStoryboard(options?[.homeStoryboard] as? UIStoryboard) // Set the LoginStoryboard - CelyWindowManager.setLoginStoryboard(options?[.LoginStoryboard] as? UIStoryboard) + CelyWindowManager.setLoginStoryboard(options?[.loginStoryboard] as? UIStoryboard) - CelyWindowManager.manager.addObserver(#selector(showScreenWith), action: .LoggedIn) - CelyWindowManager.manager.addObserver(#selector(showScreenWith), action: .LoggedOut) + CelyWindowManager.manager.addObserver(#selector(showScreenWith), action: .loggedIn) + CelyWindowManager.manager.addObserver(#selector(showScreenWith), action: .loggedOut) } // MARK: - Private Methods @@ -57,7 +57,7 @@ public class CelyWindowManager { @objc func showScreenWith(notification: NSNotification) { if let status = notification.object as? CelyStatus { - if status == .LoggedIn { + if status == .loggedIn { CelyWindowManager.manager.window.rootViewController = CelyWindowManager.manager.homeStoryboard.instantiateInitialViewController() } else { CelyWindowManager.manager.window.rootViewController = CelyWindowManager.manager.loginStoryboard.instantiateInitialViewController() diff --git a/CelyTests/CelyStorageTests.swift b/CelyTests/CelyStorageTests.swift index b698a04..d2fdfcf 100644 --- a/CelyTests/CelyStorageTests.swift +++ b/CelyTests/CelyStorageTests.swift @@ -99,9 +99,9 @@ class StorageTests: XCTestCase { dummyData.forEach { dummy in let success = store.set(dummy.value, forKey: dummy.key, securely: dummy.storeSecurely, persisted: dummy.persisted) if dummy.value != nil { - XCTAssert(success == StorageResult.Success, dummy.failedToSet()) + XCTAssert(success == StorageResult.success, dummy.failedToSet()) } else { - XCTAssert(StorageResult.Fail(.undefined) == success, "You're not supposed to be able to set nil in the storage.") + XCTAssert(StorageResult.fail(.undefined) == success, "You're not supposed to be able to set nil in the storage.") } } } diff --git a/CelyTests/CelyTests.swift b/CelyTests/CelyTests.swift index 618a4aa..14fcf84 100644 --- a/CelyTests/CelyTests.swift +++ b/CelyTests/CelyTests.swift @@ -26,9 +26,9 @@ class DummyStorage: CelyStorageProtocol { static var successful_setCalls = 0 static var successful_removeCalls = 0 func set(_ value: Any?, forKey key: String, securely secure: Bool = true, persisted: Bool = false) -> StorageResult { - if value == nil { return .Fail(.undefined) } + if value == nil { return .fail(.undefined) } DummyStorage.successful_setCalls += 1 - return .Success + return .success } func get(_ key: String) -> Any? { @@ -54,26 +54,26 @@ class CelyTests: XCTestCase { NotificationCenter.default .addObserver(self, selector: #selector(setTriggeredNotification_LoggedIn), - name: NSNotification.Name(rawValue: CelyStatus.LoggedIn.rawValue), + name: NSNotification.Name(rawValue: CelyStatus.loggedIn.rawValue), object: nil) NotificationCenter.default .addObserver(self, selector: #selector(setTriggeredNotification_LoggedOut), - name: NSNotification.Name(rawValue: CelyStatus.LoggedOut.rawValue), + name: NSNotification.Name(rawValue: CelyStatus.loggedOut.rawValue), object: nil) _properties = [.Username, .Token] Cely.setup(with: nil, forModel: DummyUser(), requiredProperties: _properties, withOptions:[ - .Storage: DummyStorage() + .storage: DummyStorage() ]) } func setTriggeredNotification_LoggedIn() { - triggeredNotification = CelyStatus.LoggedIn.rawValue + triggeredNotification = CelyStatus.loggedIn.rawValue } func setTriggeredNotification_LoggedOut() { - triggeredNotification = CelyStatus.LoggedOut.rawValue + triggeredNotification = CelyStatus.loggedOut.rawValue } override func tearDown() { @@ -92,13 +92,13 @@ class CelyTests: XCTestCase { testSetup() let status = Cely.currentLoginStatus(fromStorage:DummyStorage()) - XCTAssert(status == .LoggedIn, "User failed to have status of being .LoggedIn") + XCTAssert(status == .loggedIn, "User failed to have status of being .loggedIn") let statusWithParameters = Cely.currentLoginStatus(requiredProperties: [DummyUser.Property.Username.rawValue, DummyUser.Property.Token.rawValue], fromStorage: DummyStorage()) - XCTAssert(statusWithParameters == .LoggedIn, "User failed to have status of being .LoggedIn") + XCTAssert(statusWithParameters == .loggedIn, "User failed to have status of being .loggedIn") let notParameters = Cely.currentLoginStatus(requiredProperties: [], fromStorage: DummyStorage()) - XCTAssert(notParameters == .LoggedOut, "User failed to have status of being .LoggedIn") + XCTAssert(notParameters == .loggedOut, "User failed to have status of being .loggedIn") } func testCurrentLogin_LoggedOut_Status() { @@ -107,11 +107,11 @@ class CelyTests: XCTestCase { Cely.requiredProperties.append(DummyUser.Property.Email.rawValue) let status = Cely.currentLoginStatus(fromStorage:DummyStorage()) - XCTAssert(status == .LoggedOut, "User failed to have status of being .LoggedOut") + XCTAssert(status == .loggedOut, "User failed to have status of being .loggedOut") let statusWithParameters = Cely.currentLoginStatus(requiredProperties: [DummyUser.Property.Email.rawValue], fromStorage: DummyStorage()) - XCTAssert(statusWithParameters == .LoggedOut, "User failed to have status of being .LoggedOut") + XCTAssert(statusWithParameters == .loggedOut, "User failed to have status of being .loggedOut") } func testGetProperty() { @@ -129,20 +129,20 @@ class CelyTests: XCTestCase { } func testSaveProperty() { - XCTAssert(Cely.save(3, forKey: "number") == StorageResult.Success, "failed to save Number") - XCTAssert(Cely.save("string", forKey: "string") == StorageResult.Success, "failed to save string") - XCTAssert(Cely.save(nil, forKey: "nilValue") == StorageResult.Fail(.undefined), "failed to save nilValue") - XCTAssert(Cely.save("token", forKey: "tokenString") == StorageResult.Success, "failed to save tokenString") + XCTAssert(Cely.save(3, forKey: "number") == StorageResult.success, "failed to save Number") + XCTAssert(Cely.save("string", forKey: "string") == StorageResult.success, "failed to save string") + XCTAssert(Cely.save(nil, forKey: "nilValue") == StorageResult.fail(.undefined), "failed to save nilValue") + XCTAssert(Cely.save("token", forKey: "tokenString") == StorageResult.success, "failed to save tokenString") XCTAssert(DummyStorage.successful_setCalls == 3, "`Cely.store` and `DummyStorage` are not consistent") } func testUserAction() { - Cely.changeStatus(to: .LoggedIn) - XCTAssert(triggeredNotification == "CelyStatus.LoggedIn.user", "The .LoggedIn status didnt properly set 'triggeredNotification'") + Cely.changeStatus(to: .loggedIn) + XCTAssert(triggeredNotification == "CelyStatus.loggedIn.user", "The .loggedIn status didnt properly set 'triggeredNotification'") - Cely.changeStatus(to: .LoggedOut) - XCTAssert(triggeredNotification == "CelyStatus.LoggedOut.user", "The .LoggedOut status didnt properly set 'triggeredNotification'") + Cely.changeStatus(to: .loggedOut) + XCTAssert(triggeredNotification == "CelyStatus.loggedOut.user", "The .loggedOut status didnt properly set 'triggeredNotification'") } func testIsUserLoggedIn() { diff --git a/CelyTests/CelyWindowManagerTest.swift b/CelyTests/CelyWindowManagerTest.swift index 6fd76ca..3dba050 100644 --- a/CelyTests/CelyWindowManagerTest.swift +++ b/CelyTests/CelyWindowManagerTest.swift @@ -18,8 +18,8 @@ class CelyWindowManagerTest: XCTestCase { override func setUp() { super.setUp() CelyWindowManager.setup(window: testWindow, withOptions: [ - .HomeStoryboard: testHomeStoryboard, - .LoginStoryboard: testLoginStoryboard + .homeStoryboard: testHomeStoryboard, + .loginStoryboard: testLoginStoryboard ]) } @@ -44,10 +44,10 @@ class CelyWindowManagerTest: XCTestCase { func testShowScreen() { testMatchingHomeScreens() - Cely.changeStatus(to: .LoggedIn) + Cely.changeStatus(to: .loggedIn) XCTAssert(CelyWindowManager.manager.window.rootViewController == testHomeStoryboard.instantiateInitialViewController(), "did not properly set manager's home storyboard") - Cely.changeStatus(to: .LoggedOut) + Cely.changeStatus(to: .loggedOut) XCTAssert(CelyWindowManager.manager.window.rootViewController == testLoginStoryboard.instantiateInitialViewController(), "did not properly set manager's login storyboard") } } From bb4f5683e79f7f95bff57bd271740de241f635da Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Sat, 5 Nov 2016 09:35:11 -0500 Subject: [PATCH 08/11] Add tests --- Cely Demo/LoginStyles.swift | 8 - Cely.xcodeproj/project.pbxproj | 10 ++ Cely/CelyConstants.swift | 3 +- Cely/CelyProtocols.swift | 15 ++ .../CelyLoginViewController.swift | 29 ++-- CelyTests/ChaiOneLogo.png | Bin 0 -> 9181 bytes CelyTests/ConstantsAndProtocolTests.swift | 78 +++++++++ CelyTests/LoginViewControllerTests.swift | 148 +++++++++++++++++- 8 files changed, 269 insertions(+), 22 deletions(-) create mode 100644 CelyTests/ChaiOneLogo.png create mode 100644 CelyTests/ConstantsAndProtocolTests.swift diff --git a/Cely Demo/LoginStyles.swift b/Cely Demo/LoginStyles.swift index 1f40f36..6573d6b 100644 --- a/Cely Demo/LoginStyles.swift +++ b/Cely Demo/LoginStyles.swift @@ -11,14 +11,6 @@ import Cely struct LoginStyles: CelyStyle { - func backgroundColor() -> UIColor { - return .red - } - - func textFieldBackgroundColor() -> UIColor { - return .blue - } - func appLogo() -> UIImage? { return UIImage(named: "ChaiOneLogo") } diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index e4d198f..141af57 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -37,6 +37,9 @@ 31D9B96E1DCD748F0039BCB8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */; }; 31DA8A581DCD8E8F0006C598 /* LoginStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */; }; 31DAA33E1DB289220040B266 /* CelyWindowManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */; }; + 31DB1FEB1DCE111900BE1D1A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */; }; + 31DB1FED1DCE132200BE1D1A /* ChaiOneLogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 31DB1FEC1DCE132200BE1D1A /* ChaiOneLogo.png */; }; + 31DB1FEF1DCE226700BE1D1A /* ConstantsAndProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DB1FEE1DCE226700BE1D1A /* ConstantsAndProtocolTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -122,6 +125,8 @@ 31D9B96D1DCD748F0039BCB8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "Supporting Files/Assets.xcassets"; sourceTree = ""; }; 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginStyles.swift; sourceTree = ""; }; 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CelyWindowManagerTest.swift; sourceTree = ""; }; + 31DB1FEC1DCE132200BE1D1A /* ChaiOneLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ChaiOneLogo.png; sourceTree = ""; }; + 31DB1FEE1DCE226700BE1D1A /* ConstantsAndProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstantsAndProtocolTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -193,9 +198,11 @@ 1FB2B23D1DB1751600716E80 /* CelyTests */ = { isa = PBXGroup; children = ( + 31DB1FEC1DCE132200BE1D1A /* ChaiOneLogo.png */, 1FABFAEC1DBE727F0096DD36 /* TestMain.storyboard */, 1FB2B23E1DB1751600716E80 /* CelyTests.swift */, 1F9E55C21DC2426000435B52 /* LoginViewControllerTests.swift */, + 31DB1FEE1DCE226700BE1D1A /* ConstantsAndProtocolTests.swift */, 1F0C13341DB188AB00AC1C94 /* CelyStorageTests.swift */, 31DAA33D1DB289220040B266 /* CelyWindowManagerTest.swift */, 1FB2B2401DB1751600716E80 /* Info.plist */, @@ -389,6 +396,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31DB1FED1DCE132200BE1D1A /* ChaiOneLogo.png in Resources */, + 31DB1FEB1DCE111900BE1D1A /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -440,6 +449,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31DB1FEF1DCE226700BE1D1A /* ConstantsAndProtocolTests.swift in Sources */, 1F9E55C31DC2426000435B52 /* LoginViewControllerTests.swift in Sources */, 1F0C13351DB188AB00AC1C94 /* CelyStorageTests.swift in Sources */, 1FB2B23F1DB1751600716E80 /* CelyTests.swift in Sources */, diff --git a/Cely/CelyConstants.swift b/Cely/CelyConstants.swift index e4d7a4a..95a3c80 100644 --- a/Cely/CelyConstants.swift +++ b/Cely/CelyConstants.swift @@ -55,9 +55,8 @@ internal extension UITextField { get { if let l = leftView { return l.frame.size.width - } else { - return 0 } + return 0 } set { leftViewMode = .always leftView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height)) diff --git a/Cely/CelyProtocols.swift b/Cely/CelyProtocols.swift index 0712a0a..b8cffd0 100644 --- a/Cely/CelyProtocols.swift +++ b/Cely/CelyProtocols.swift @@ -31,22 +31,37 @@ public protocol CelyStyle { public extension CelyStyle { + /// Background Color for default login screen + /// + /// - returns: UIColor func backgroundColor() -> UIColor { return .white } + /// Background Color for textfields + /// + /// - returns: UIColor func textFieldBackgroundColor() -> UIColor { return .white } + /// Background Color for login button + /// + /// - returns: UIColor func buttonBackgroundColor() -> UIColor { return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) } + /// Text Color for login button + /// + /// - returns: UIColor func buttonTextColor() -> UIColor { return .white } + /// App icon for default login screen + /// + /// - returns: UIImage? func appLogo() -> UIImage? { return UIImage(named: "CelyLogo") } diff --git a/Cely/Supporting Files/CelyLoginViewController.swift b/Cely/Supporting Files/CelyLoginViewController.swift index fe385fd..9ac8bb9 100644 --- a/Cely/Supporting Files/CelyLoginViewController.swift +++ b/Cely/Supporting Files/CelyLoginViewController.swift @@ -17,7 +17,7 @@ class CelyLoginViewController: UIViewController { @IBOutlet weak var passwordField: UITextField? @IBOutlet weak var loginButton: UIButton? @IBOutlet var textFields: [UITextField]? - @IBOutlet fileprivate weak var bottomLayoutConstraint: NSLayoutConstraint! + @IBOutlet weak var bottomLayoutConstraint: NSLayoutConstraint! // MARK: - Variables var initialBottomConstant: CGFloat! @@ -76,23 +76,30 @@ internal extension CelyLoginViewController { name: .UIKeyboardWillChangeFrame, object: nil) } - func keyboardNotification(notification: NSNotification) { - let userInfo = notification.userInfo! + func convertNotification(notification: NSNotification) -> (duration: Double, endFrame: CGRect, animationCurve: UIViewAnimationOptions)? { - guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, - let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue, - let rawCurve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as? NSNumber else { return } + guard let userInfo = notification.userInfo, + let duration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue, + let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, + let rawCurve = (notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uint32Value else { return nil } - let animationDuration = (duration).doubleValue - let keyboardEndFrame = (endFrame).cgRectValue - let convertedKeyboardEndFrame = view.convert(keyboardEndFrame, from: view.window) - let rawAnimationCurve = (rawCurve).uint32Value << 16 + let rawAnimationCurve = rawCurve << 16 let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) + return (duration, endFrame, animationCurve) + } + + func keyboardNotification(notification: NSNotification) { + + guard let (duration, endFrame, animationCurve) = convertNotification(notification: notification) else { + return + } + + let convertedKeyboardEndFrame = view.convert(endFrame, from: view.window) let newConstraint = view.bounds.maxY - convertedKeyboardEndFrame.minY bottomLayoutConstraint.constant = newConstraint == 0 ? initialBottomConstant : newConstraint - UIView.animate(withDuration: animationDuration, + UIView.animate(withDuration: duration, delay: 0.0, options: [.beginFromCurrentState, animationCurve], animations: { diff --git a/CelyTests/ChaiOneLogo.png b/CelyTests/ChaiOneLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..e58c1d376b4c4b509c90de730da938fb7b0cda6d GIT binary patch literal 9181 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 UIColor { + return .brown + } + func buttonTextColor() -> UIColor { + return .black + } + func buttonBackgroundColor() -> UIColor { + return .white + } + func textFieldBackgroundColor() -> UIColor { + return .yellow + } + func appLogo() -> UIImage? { + return UIImage(named: "ChaiOneLogo.png") + } +} + class LoginViewControllerTests: XCTestCase { var loginVC: CelyLoginViewController! + let testDummy = DummyStyles() override func setUp() { super.setUp() - + CelyWindowManager.manager.loginStyle = DummyStyles() loginVC = CelyLoginViewController() + loginVC.usernameField = UITextField() loginVC.usernameField?.tag = 0 loginVC.passwordField = UITextField() loginVC.passwordField?.tag = 1 loginVC.textFields = [loginVC.usernameField!, loginVC.passwordField!] + loginVC.viewDidLoad() } override func tearDown() { super.tearDown() } +} +// MARK: - Test View LifeCycle +extension LoginViewControllerTests { func testViewDidLoad() { loginVC.viewDidLoad() @@ -40,6 +64,20 @@ class LoginViewControllerTests: XCTestCase { } } + func testViewDidAppear() { + + let constraint = NSLayoutConstraint() + constraint.constant = 20 + loginVC.bottomLayoutConstraint = constraint + loginVC.viewDidAppear(true) + + XCTAssertEqual(loginVC.initialBottomConstant, 20, "Failed to properly call viewDidAppear") + } +} + +// MARK: - Test IBOutlets +extension LoginViewControllerTests { + func testDidPressLogin() { loginVC.usernameField?.text = "username" @@ -63,6 +101,114 @@ class LoginViewControllerTests: XCTestCase { XCTAssert(passwordBoolVal, "failed to return password textfield.") XCTAssert(!loginVC.passwordField!.isFirstResponder, "failed to remove first responder on password field.") + } +} + +// MARK: - Test Styles +extension LoginViewControllerTests { + + func testViewBackgroundColor() { + XCTAssertEqual(loginVC.styles.backgroundColor(), testDummy.backgroundColor(), "view.backgroundColor was not properly set") + } + + func testTextFieldBackgroundColor() { + XCTAssertEqual(loginVC.styles.textFieldBackgroundColor(), testDummy.textFieldBackgroundColor(), "textFields backgroundColor was not properly set") + } + + func testButtonBackgroundColor() { + XCTAssertEqual(loginVC.styles.buttonBackgroundColor(), testDummy.buttonBackgroundColor(), "loginButton.backgroundColor was not properly set") + } + + func testButtonTextColor() { + XCTAssertEqual(loginVC.styles.buttonTextColor(), testDummy.buttonTextColor(), "loginButton.titleColor was not properly set") + } + + func testAppLogo() { + XCTAssertEqual(loginVC.styles.appLogo(), testDummy.appLogo(), "appImageView was not properly set") + } +} + +// MARK: - Test Notifications +extension LoginViewControllerTests { + + func testConvertNotification_Failure() { + let fakeUserInfo: [AnyHashable : Any] = [ + UIKeyboardAnimationDurationUserInfoKey : "FORCE FAIL", + UIKeyboardFrameEndUserInfoKey : NSValue(cgRect: .zero), + UIKeyboardAnimationCurveUserInfoKey : NSNumber(value: 30) + ] + + let fakeNotification = NSNotification(name: .UIKeyboardWillChangeFrame, object: nil, userInfo: fakeUserInfo) + + let converted = loginVC.convertNotification(notification: fakeNotification) + + XCTAssertNil(converted, "convertNotification was supposed to return nil") + } + + func testConvertNotification_Success() { + + let fakeUserInfo: [AnyHashable : Any] = [ + UIKeyboardAnimationDurationUserInfoKey : NSNumber(value: 20), + UIKeyboardFrameEndUserInfoKey : NSValue(cgRect: .zero), + UIKeyboardAnimationCurveUserInfoKey : NSNumber(value: 30) + ] + + let fakeNotification = NSNotification(name: .UIKeyboardWillChangeFrame, object: nil, userInfo: fakeUserInfo) + + let converted = loginVC.convertNotification(notification: fakeNotification) + + XCTAssertEqual(converted?.duration, 20, "failed to set duration") + XCTAssert(type(of: converted!.duration) == Double.self, "duration is not of type Double.") + + XCTAssertEqual(converted?.endFrame, .zero, "failed to set endFrame") + XCTAssert(type(of: converted!.endFrame) == CGRect.self, "endFrame is not of type CGRect.") + + XCTAssertEqual(converted?.animationCurve, UIViewAnimationOptions(rawValue: UInt(30) << 16), "failed to set duration") + XCTAssert(type(of: converted!.animationCurve) == UIViewAnimationOptions.self, "animationCurve is not of type UIViewAnimationOptions.") + + print(converted) + } + + func testKeyboardNotification_Success() { + + let constraint = NSLayoutConstraint() + loginVC.bottomLayoutConstraint = constraint + loginVC.bottomLayoutConstraint.constant = 20 + + let fakeUserInfo: [AnyHashable : Any] = [ + UIKeyboardAnimationDurationUserInfoKey : NSNumber(value: 20), + UIKeyboardFrameEndUserInfoKey : NSValue(cgRect: CGRect(x: 0, y: 200, width: 320, height: 500)), + UIKeyboardAnimationCurveUserInfoKey : NSNumber(value: 30) + ] + + let fakeNotification = NSNotification(name: .UIKeyboardWillChangeFrame, object: nil, userInfo: fakeUserInfo) + + loginVC.keyboardNotification(notification: fakeNotification) + + // I simply ran this and paused inside of `keyboardNotification` to find value + let correctValue: CGFloat = 467 + + XCTAssertEqual(loginVC.bottomLayoutConstraint.constant, correctValue, "bottomLayoutConstraint is supposed to be \(correctValue)") + } + + func testKeyboardNotification_Failure() { + + let constraint = NSLayoutConstraint() + loginVC.bottomLayoutConstraint = constraint + loginVC.bottomLayoutConstraint.constant = 20 + + let fakeUserInfo: [AnyHashable : Any] = [ + UIKeyboardAnimationDurationUserInfoKey : "FORCE FAIL", + UIKeyboardFrameEndUserInfoKey : NSValue(cgRect: CGRect(x: 0, y: 200, width: 320, height: 500)), + UIKeyboardAnimationCurveUserInfoKey : NSNumber(value: 30) + ] + + let fakeNotification = NSNotification(name: .UIKeyboardWillChangeFrame, object: nil, userInfo: fakeUserInfo) + + loginVC.keyboardNotification(notification: fakeNotification) + + let converted = loginVC.convertNotification(notification: fakeNotification) + XCTAssertNil(converted, "convertNotification was supposed to return nil") } } From 85d7c36faae717d28a4bc99f2553f2dc8fdaae42 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Sat, 5 Nov 2016 14:34:04 -0500 Subject: [PATCH 09/11] finish writing documentation 1.0 --- Cely Demo/AppDelegate.swift | 10 -- Cely Demo/Base.lproj/Main.storyboard | 4 +- Cely Demo/User.swift | 13 +-- Cely.xcodeproj/project.pbxproj | 2 +- Images/CelyLogo.png | Bin 0 -> 18104 bytes Images/CelyLogo@2x.png | Bin 0 -> 40824 bytes Images/READMEHeader.png | Bin 0 -> 33601 bytes README.md | 150 ++++++++++++++++++++------- 8 files changed, 119 insertions(+), 60 deletions(-) create mode 100644 Images/CelyLogo.png create mode 100644 Images/CelyLogo@2x.png create mode 100644 Images/READMEHeader.png diff --git a/Cely Demo/AppDelegate.swift b/Cely Demo/AppDelegate.swift index 8e2c3f0..462b94f 100644 --- a/Cely Demo/AppDelegate.swift +++ b/Cely Demo/AppDelegate.swift @@ -17,16 +17,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.Token], withOptions: [ - .loginStyle: LoginStyles(), - .loginCompletionBlock: { (username: String, password: String) in - if username == "asdf" && password == "asdf" { - Cely.save(username, forKey: "username", persisted: true) - Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true) - Cely.changeStatus(to: .loggedIn) - } - } - ]) return true } diff --git a/Cely Demo/Base.lproj/Main.storyboard b/Cely Demo/Base.lproj/Main.storyboard index f8c6cb4..9130d4e 100644 --- a/Cely Demo/Base.lproj/Main.storyboard +++ b/Cely Demo/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/Cely Demo/User.swift b/Cely Demo/User.swift index 3f8883e..bf58d04 100644 --- a/Cely Demo/User.swift +++ b/Cely Demo/User.swift @@ -11,17 +11,14 @@ import Cely struct User: CelyUser { - private init() {} - static let ref = User() - enum Property: CelyProperty { - case Username = "username" - case Email = "email" - case Token = "token" + case username = "username" + case email = "email" + case token = "token" func securely() -> Bool { switch self { - case .Token: + case .token: return true default: return false @@ -30,7 +27,7 @@ struct User: CelyUser { func persisted() -> Bool { switch self { - case .Username: + case .username: return true default: return false diff --git a/Cely.xcodeproj/project.pbxproj b/Cely.xcodeproj/project.pbxproj index 141af57..1e0b623 100644 --- a/Cely.xcodeproj/project.pbxproj +++ b/Cely.xcodeproj/project.pbxproj @@ -234,11 +234,11 @@ children = ( 31358EBF1DB31CA800AC7119 /* Locksmith.framework */, 31358EA91DB31BC400AC7119 /* AppDelegate.swift */, + 311B1F2B1DB31FF6005A155B /* User.swift */, 31358EAB1DB31BC400AC7119 /* ViewController.swift */, 31DA8A571DCD8E8F0006C598 /* LoginStyles.swift */, 311B1F2D1DB3230F005A155B /* SettingsViewController.swift */, 31DA8A561DCD8E600006C598 /* Supporting Files */, - 311B1F2B1DB31FF6005A155B /* User.swift */, ); path = "Cely Demo"; sourceTree = ""; diff --git a/Images/CelyLogo.png b/Images/CelyLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..636a5ac2268d82afefc543bd5884139114a902e3 GIT binary patch literal 18104 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 JtaD0e0sx`KWn=&V literal 0 HcmV?d00001 diff --git a/Images/CelyLogo@2x.png b/Images/CelyLogo@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b7b5f363e331202c75f8827042b4eab5fc3ed1e5 GIT binary patch literal 40824 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 YM!bk{e80c^V=C}>38|}Aa=|L#KloENRsaA1 literal 0 HcmV?d00001 diff --git a/Images/READMEHeader.png b/Images/READMEHeader.png new file mode 100644 index 0000000000000000000000000000000000000000..19c5d2b0f714b27223e76cb4b452a2104f590d47 GIT binary patch literal 33601 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 YADIdJJ%fQ)AkrZM$oT_;`ik!J+b5Cy%I}2#< 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 9003d04..65d56ae 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ +

+ ![bitrise status](https://www.bitrise.io/app/aff729145cb46dfe.svg?token=YUV0bymd7P_w2tdiKw2xOQ&branch=master) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![codecov](https://codecov.io/gh/chaione/cely/branch/master/graph/badge.svg)](https://codecov.io/gh/chaione/cely) - -#Cely (WIP) - -Plug-n-Play iOS login framework written in Swift. - +> Prounounced Cell-Lee ## Overview -Cely's goal is to add a login system into your up in under 20 seconds! +Cely's goal is to add a login system into your app in under 30 seconds! ## Background -There are many **How to build a login system for iOS** tutorials on the web that tell you to store credentials in NSUserDefaults, which is incorrect, credentials need to be stored in Keychain. Now working with Keychain is not very fun, that's why Cely is built on top of [Locksmith](https://github.com/matthewpalmer/Locksmith), swift's most popular Keychain wrapper. Cely makes adding a login system to your application as simple as dropping in a UITableView. +Whether you're building an app for a client or for a hackathon, building a login system, no matter how basic it is, can be very tedious and time-consuming. Cely's architecture has been battle tested on countless apps, and Cely guarantees you a fully functional login system in a fraction of the time. You can trust Cely is handling login credentials correctly as well since Cely is built on top of [Locksmith](https://github.com/matthewpalmer/Locksmith), swift's most popular Keychain wrapper. + + ###Details: What does Cely does for you? 1. Simple API to store user creditials and information **securely** -2. Manages switching between Login Screen and your apps Home Screen -3. Customizable starter Login screen +2. Manages switching between your app's Home Screen and Login Screen +3. Customizable starter Login screen(or you can use your login screen) What Cely **does not do** for you? @@ -27,12 +27,6 @@ What Cely **does not do** for you? 2. Handle Network errors 3. Anything with the network -# Customizable login screen(WIP) - -- textboxes -- background image(and or)color -- email/password keyboard - ## Usage ###Setup(20 seconds) @@ -48,7 +42,7 @@ import Cely struct User: CelyUser { enum Property : CelyProperty { - case Token = "token" + case token = "token" } } @@ -64,7 +58,7 @@ import Cely func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: Any]?) -> Bool { - Cely.setup(with: window, forModel: User(), requiredProperties: [.Token]) + Cely.setup(with: window, forModel: User(), requiredProperties: [.token]) ... } @@ -72,25 +66,86 @@ func application(application: UIApplication, didFinishLaunchingWithOptions launc **Hit RUN!!** -### Handle LoginCallback -Now how do we get the `username` and `password` from Cely's default LoginViewController? It's easy, just pass in a completion block in the options. +### CelyOptions +#### Handle Login Credentials +Now how do we get the `username` and `password` from Cely's default LoginViewController? It's easy, just pass in a completion block for the `.loginCompletionBlock`. Check out [`CelyOptions`](#Cely.CelyOptions) for more info. ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.Token], withOptions: [ - .LoginCompletionBlock: { (username: String, password: String) in + Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [ + .loginCompletionBlock: { (username: String, password: String) in if username == "asdf" && password == "asdf" { Cely.save(username, forKey: "username") Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true) - Cely.changeStatus(to: .LoggedIn) + Cely.changeStatus(to: .loggedIn) } } ]) return true } +``` +#### Customize Default Login Screen + +Create an object that conforms to the [`CelyStyle`](#Cely.CelyStyle) protocol and set it to `.loginStyle` inside of the [`CelyOptions`](#Cely.CelyOptions) dictionary when calling Cely's [`setup(_:)`](#Cely.setup) method. + +```swift +// AppLoginStyles.swift +struct AppLoginStyles: CelyStyle { + func backgroundColor() -> UIColor { + return .white + } + func buttonTextColor() -> UIColor { + return .white + } + func buttonBackgroundColor() -> UIColor { + return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) + } + func textFieldBackgroundColor() -> UIColor { + return .white + } + func appLogo() -> UIImage? { + return UIImage(named: "CelyLogo") + } +} + +... + +// AppDelegate.swift + +func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [ + .loginStyles: AppLoginStyles(), // <--- HERE!! + .loginCompletionBlock: { ... } + ]) + + return true +} + +``` + +#### Use your own Login Screen +To use your own login screen, simply create a storyboard that contains your login screen and set it to `.loginStoryboard` inside of the [`CelyOptions`](#Cely.CelyOptions) dictionary when calling Cely's [`setup(_:)`](#Cely.setup) method. Oh and if your app uses a different storyboard other than `Main.storyboard`, you can pass that in as `.homeStoryboard`. + +**⚠️⚠️⚠️⚠️ Be sure to make your Login screen as the `InitialViewController` inside of your storyboard!⚠️⚠️⚠️⚠️** + +```swift + +// AppDelegate.swift + +func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [ + .loginStoryboard: UIStoryboard(name: "MyCustomLogin", bundle: nil), + .homeStoryboard: UIStoryboard(name: "NonMain", bundle: nil) + ]) + + return true +} + ``` ###Recommended User Pattern @@ -101,13 +156,13 @@ import Cely struct User: CelyUser { enum Property: CelyProperty { - case Username = "username" - case Email = "email" - case Token = "token" + case username = "username" + case email = "email" + case token = "token" func securely() -> Bool { switch self { - case .Token: + case .token: return true default: return false @@ -116,7 +171,7 @@ struct User: CelyUser { func persisted() -> Bool { switch self { - case .Username: + case .username: return true default: return false @@ -162,14 +217,14 @@ ApiManager.logUserIn("username", "password") { json in let apiToken = json["token"].string // REAL CODE!!! - User.save(apiToken, as: .Token) + User.save(apiToken, as: .token) } ``` and getting data as simple as: ```swift -let token = User.get(.Token) +let token = User.get(.token) ``` ##API @@ -191,11 +246,11 @@ Sets up Cely within your application Example ```swift -Cely.setup(with: window, forModel: User(), requiredProperties:[.Token]) +Cely.setup(with: window, forModel: User(), requiredProperties:[.token]) // or -Cely.setup(with: window, forModel: User(), requiredProperties:[.Token], withOptions:[ +Cely.setup(with: window, forModel: User(), requiredProperties:[.token], withOptions:[ .LoginStoryboard: UIStoryboard(name: "MyCustomLogin", bundle: nil), .HomeStoryboard: UIStoryboard(name: "My_NonMain_Storyboard", bundle: nil), .LoginCompletionBlock: { (username: String, password: String) in @@ -408,6 +463,23 @@ func removeAllData() ``` +
+##### `CelyStyle` +The `protocol` an object must conform to in order to customize Cely's default login screen. Since all methods are optional, Cely will use the default value for any unimplemented methods. + +
+Methods + +```swift +func backgroundColor() -> UIColor +func textFieldBackgroundColor() -> UIColor +func buttonBackgroundColor() -> UIColor +func buttonTextColor() -> UIColor +func appLogo() -> UIImage? + +``` +
+ #### Typealias
##### `CelyProperty ` @@ -427,10 +499,10 @@ func removeAllData() Case || ----|------| -`Storage ` | Pass in you're own storage class if you wish not to use Cely's default storage. Class must conform to the `CelyStorage` protocol. -`HomeStoryboard ` | Pass in your app's default storyboard if it is not named "Main" -`LoginStoryboard ` | Pass in your own login storyboard. -`LoginCompletionBlock ` | `(String,String) -> Void` block of code that will run once the Login button is pressed on Cely's default login Controller +`storage ` | Pass in you're own storage class if you wish not to use Cely's default storage. Class must conform to the `CelyStorage` protocol. +`homeStoryboard ` | Pass in your app's default storyboard if it is not named "Main" +`loginStoryboard ` | Pass in your own login storyboard. +`loginCompletionBlock ` | `(String,String) -> Void` block of code that will run once the Login button is pressed on Cely's default login Controller
@@ -442,8 +514,8 @@ Case || Case || ----|------| -`LoggedIn ` | Indicates user is now logged in. -`LoggedOut ` | Indicates user is now logged out. +`loggedIn ` | Indicates user is now logged in. +`loggedOut ` | Indicates user is now logged out. @@ -456,8 +528,8 @@ Case || Case || ----|------| -`Success ` | Successfully saved your data -`Fail(error) ` | Failed to save data along with a `LocksmithError`. +`success ` | Successfully saved your data +`fail(error) ` | Failed to save data along with a `LocksmithError`. From 7b1cad1ddcc956eacb58bc1c95556010eee47f23 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Sat, 5 Nov 2016 15:02:01 -0500 Subject: [PATCH 10/11] Update Documentation 2.0 --- Cely Demo/AppDelegate.swift | 12 +++++++ Cely Demo/User.swift | 24 +++++++++++-- README.md | 69 +++++++++++++++++++------------------ 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/Cely Demo/AppDelegate.swift b/Cely Demo/AppDelegate.swift index 462b94f..e33a4c7 100644 --- a/Cely Demo/AppDelegate.swift +++ b/Cely Demo/AppDelegate.swift @@ -17,6 +17,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + Cely.setup(with: window!, forModel: User(), requiredProperties: [.token], withOptions: [ + .loginStyle: CottonCandy(), + .loginCompletionBlock: { (username: String, password: String) in + if username == "asdf" && password == "asdf" { + User.save(username, as: .token) + let token = User.get(.token) + Cely.save(username, forKey: "username") + Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true) + Cely.changeStatus(to: .loggedIn) + } + } + ]) return true } diff --git a/Cely Demo/User.swift b/Cely Demo/User.swift index bf58d04..f9d2e6d 100644 --- a/Cely Demo/User.swift +++ b/Cely Demo/User.swift @@ -48,17 +48,35 @@ struct User: CelyUser { extension User { - static func save(value: Any, as property: Property) { + static func save(_ value: Any, as property: Property) { property.save(value: value) } - static func save(data: [Property : Any]) { + static func save(_ data: [Property : Any]) { data.forEach { property, value in property.save(value) } } - static func get(property: Property) -> Any? { + static func get(_ property: Property) -> Any? { return property.get() } } + +struct CottonCandy: CelyStyle { + func backgroundColor() -> UIColor { + return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) // Changing Color + } + func buttonTextColor() -> UIColor { + return .white + } + func buttonBackgroundColor() -> UIColor { + return UIColor(red: 253/255, green: 108/255, blue: 179/255, alpha: 1) // Changing Color + } + func textFieldBackgroundColor() -> UIColor { + return UIColor.white.withAlphaComponent(0.4) + } + func appLogo() -> UIImage? { + return UIImage(named: "CelyLogo") + } +} diff --git a/README.md b/README.md index 65d56ae..7862013 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@
+![Swift 3.0](https://img.shields.io/badge/Swift-3.0-orange.svg?style=flat) ![bitrise status](https://www.bitrise.io/app/aff729145cb46dfe.svg?token=YUV0bymd7P_w2tdiKw2xOQ&branch=master) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![codecov](https://codecov.io/gh/chaione/cely/branch/master/graph/badge.svg)](https://codecov.io/gh/chaione/cely) @@ -27,6 +28,24 @@ What Cely **does not do** for you? 2. Handle Network errors 3. Anything with the network +## Requirements +- Xcode 8 +- swift 3.0 + +## Installation + +###Carthage +``` +github "ChaiOne/Cely" +``` +Cely will also include [`Locksmith`](https://github.com/matthewpalmer/Locksmith) when you import it into your project, so be sure to add `Locksmith` in your copy phase script. + +> $(SRCROOT)/Carthage/Build/iOS/Cely.framework +> $(SRCROOT)/Carthage/Build/iOS/Locksmith.framework + +####Keychain entitlement Part(Xcode 8 bug?) +Be sure to [turn on Keychain entitlements](http://stackoverflow.com/a/31421742/1973339) for your app, not doing so will prevent Cely from saving data to the keychain. + ## Usage ###Setup(20 seconds) @@ -41,7 +60,7 @@ import Cely struct User: CelyUser { - enum Property : CelyProperty { + enum Property: CelyProperty { case token = "token" } } @@ -74,7 +93,7 @@ Now how do we get the `username` and `password` from Cely's default LoginViewCon func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [ + Cely.setup(with: window!, forModel: User(), requiredProperties: [.token], withOptions: [ .loginCompletionBlock: { (username: String, password: String) in if username == "asdf" && password == "asdf" { Cely.save(username, forKey: "username") @@ -92,19 +111,19 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau Create an object that conforms to the [`CelyStyle`](#Cely.CelyStyle) protocol and set it to `.loginStyle` inside of the [`CelyOptions`](#Cely.CelyOptions) dictionary when calling Cely's [`setup(_:)`](#Cely.setup) method. ```swift -// AppLoginStyles.swift -struct AppLoginStyles: CelyStyle { +// LoginStyles.swift +struct CottonCandy: CelyStyle { func backgroundColor() -> UIColor { - return .white + return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) // Changing Color } func buttonTextColor() -> UIColor { return .white } func buttonBackgroundColor() -> UIColor { - return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) + return UIColor(red: 253/255, green: 108/255, blue: 179/255, alpha: 1) // Changing Color } func textFieldBackgroundColor() -> UIColor { - return .white + return UIColor.white.withAlphaComponent(0.4) } func appLogo() -> UIImage? { return UIImage(named: "CelyLogo") @@ -118,7 +137,7 @@ struct AppLoginStyles: CelyStyle { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Cely.setup(with: window!, forModel: User.ref, requiredProperties: [.token], withOptions: [ - .loginStyles: AppLoginStyles(), // <--- HERE!! + .loginStyle: CottonCandy(), // <--- HERE!! .loginCompletionBlock: { ... } ]) @@ -127,8 +146,10 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau ``` -#### Use your own Login Screen -To use your own login screen, simply create a storyboard that contains your login screen and set it to `.loginStoryboard` inside of the [`CelyOptions`](#Cely.CelyOptions) dictionary when calling Cely's [`setup(_:)`](#Cely.setup) method. Oh and if your app uses a different storyboard other than `Main.storyboard`, you can pass that in as `.homeStoryboard`. +#### Use your own Screens +To use your own login screen, simply create a storyboard that contains your login screen and pass that in as `.loginStoryboard` inside of the [`CelyOptions`](#Cely.CelyOptions) dictionary when calling Cely's [`setup(_:)`](#Cely.setup) method. + +Lastly, if your app uses a different storyboard other than `Main.storyboard`, you can pass that in as `.homeStoryboard`. **⚠️⚠️⚠️⚠️ Be sure to make your Login screen as the `InitialViewController` inside of your storyboard!⚠️⚠️⚠️⚠️** @@ -192,17 +213,17 @@ struct User: CelyUser { extension User { - static func save(value: Any, as property: Property) { + static func save(_ value: Any, as property: Property) { property.save(value: value) } - static func save(data: [Property : Any]) { + static func save(_ data: [Property : Any]) { data.forEach { property, value in property.save(value) } } - static func get(property: Property) -> Any? { + static func get(_ property: Property) -> Any? { return property.get() } } @@ -230,7 +251,7 @@ let token = User.get(.token) ##API ###Cely -Cely was made to help handle user credentials and handling login with ease. Below you will find documentation for Cely's Framework. +Cely was made to help handle user credentials and handling login with ease. Below you will find documentation for Cely's Framework. **Please do not hesitate to open an issue if something is unclear or is missing.** #### Variables
##### `store` @@ -502,6 +523,7 @@ Case || `storage ` | Pass in you're own storage class if you wish not to use Cely's default storage. Class must conform to the `CelyStorage` protocol. `homeStoryboard ` | Pass in your app's default storyboard if it is not named "Main" `loginStoryboard ` | Pass in your own login storyboard. +`loginStyle` | Pass in an object that conforms to [`CelyStyle`](#Cely.CelyStyle) to customize the default login screen. `loginCompletionBlock ` | `(String,String) -> Void` block of code that will run once the Login button is pressed on Cely's default login Controller @@ -533,25 +555,6 @@ Case || - -## Requirements -- Xcode 8 -- swift 3.0 - -## Installation - -###Carthage -``` -github "ChaiOne/Cely" -``` -Cely will also include [`Locksmith`](https://github.com/matthewpalmer/Locksmith) when you import it into your project, so be sure to add `Locksmith` in your copy phase script. - -> $(SRCROOT)/Carthage/Build/iOS/Cely.framework -> $(SRCROOT)/Carthage/Build/iOS/Locksmith.framework - -####Keychain entitlement Part(Xcode 8 bug?) -Be sure to [turn on Keychain entitlements](http://stackoverflow.com/a/31421742/1973339) for your app, not doing so will prevent Cely from saving data to the keychain. - ## License Cely is available under the MIT license. See the LICENSE file for more info. From 4aff6dc8856f56867e57ae1629698f1b455edaf3 Mon Sep 17 00:00:00 2001 From: Fabian Buentello Date: Sat, 5 Nov 2016 15:24:10 -0500 Subject: [PATCH 11/11] finish documentation --- Cartfile | 2 +- Cely Demo/AppDelegate.swift | 3 --- Cely Demo/User.swift | 18 ------------------ 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/Cartfile b/Cartfile index 2823a0c..a2f1a32 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "matthewpalmer/Locksmith" \ No newline at end of file +github "matthewpalmer/Locksmith" ~> 3.0 \ No newline at end of file diff --git a/Cely Demo/AppDelegate.swift b/Cely Demo/AppDelegate.swift index e33a4c7..702b9cf 100644 --- a/Cely Demo/AppDelegate.swift +++ b/Cely Demo/AppDelegate.swift @@ -18,11 +18,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Cely.setup(with: window!, forModel: User(), requiredProperties: [.token], withOptions: [ - .loginStyle: CottonCandy(), .loginCompletionBlock: { (username: String, password: String) in if username == "asdf" && password == "asdf" { - User.save(username, as: .token) - let token = User.get(.token) Cely.save(username, forKey: "username") Cely.save("FAKETOKEN:\(username)\(password)", forKey: "token", securely: true) Cely.changeStatus(to: .loggedIn) diff --git a/Cely Demo/User.swift b/Cely Demo/User.swift index f9d2e6d..69156d3 100644 --- a/Cely Demo/User.swift +++ b/Cely Demo/User.swift @@ -62,21 +62,3 @@ extension User { return property.get() } } - -struct CottonCandy: CelyStyle { - func backgroundColor() -> UIColor { - return UIColor(red: 86/255, green: 203/255, blue: 249/255, alpha: 1) // Changing Color - } - func buttonTextColor() -> UIColor { - return .white - } - func buttonBackgroundColor() -> UIColor { - return UIColor(red: 253/255, green: 108/255, blue: 179/255, alpha: 1) // Changing Color - } - func textFieldBackgroundColor() -> UIColor { - return UIColor.white.withAlphaComponent(0.4) - } - func appLogo() -> UIImage? { - return UIImage(named: "CelyLogo") - } -}