Last active
October 17, 2016 21:29
-
-
Save jaclync/15fd3a69bee084237a07084bb6c43bcc to your computer and use it in GitHub Desktop.
jaclyn/swift2.3..develop.diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Quizlet-iPhone/AssistantModeViewController.swift b/Quizlet-iPhone/AssistantModeViewController.swift | |
index 6e68996..c739fba 100644 | |
--- a/Quizlet-iPhone/AssistantModeViewController.swift | |
+++ b/Quizlet-iPhone/AssistantModeViewController.swift | |
@@ -20,7 +20,7 @@ class AssistantModeAnimator: NSObject, UIViewControllerAnimatedTransitioning { | |
let toView = toViewController.view | |
let fromView = fromViewController.view | |
- let containerView = transitionContext.containerView()! | |
+ let containerView = transitionContext.containerView() | |
let destinationRect = containerView.convertRect(fromView.bounds, fromView: fromView) | |
toView.frame = destinationRect | |
@@ -87,8 +87,11 @@ class AssistantModeTransitionContext : NSObject, UIViewControllerContextTransiti | |
completionBlock?(didComplete) | |
} | |
- func containerView() -> UIView? { | |
- return _containerView | |
+ func containerView() -> UIView { | |
+ guard let containerView = _containerView else { | |
+ fatalError("Cannot find container view") | |
+ } | |
+ return containerView | |
} | |
func isAnimated() -> Bool { | |
@@ -118,6 +121,10 @@ class AssistantModeTransitionContext : NSObject, UIViewControllerContextTransiti | |
func cancelInteractiveTransition() { | |
// no-op | |
} | |
+ | |
+ func pauseInteractiveTransition() { | |
+ // no-op | |
+ } | |
} | |
/// Assistant mode entry view controller. | |
@@ -154,17 +161,17 @@ class AssistantModeViewController: QLModeViewController, ContainerViewController | |
} | |
} | |
private let studySettingTransformer: AssistantModeStudySettingTransformer | |
- private let studySettingsService: StudySettingsService | |
+ private let studySettingsService: StudySettingsService? | |
private let disposeBag: DisposeBag = DisposeBag() | |
- convenience init(audioManager: QLAudioManager, featureFlagManager: QLFeatureFlagManager, starredOnly: Bool, studyObject: QLStudyObject, studySettings: [QLStudySetting]?, studySettingsService: StudySettingsService, userDefaultsManager: UserDefaultsManager, userManager: QLUserManager, viewControllerFactory: QLViewControllerFactory) { | |
+ convenience init(audioManager: QLAudioManager, featureFlagManager: QLFeatureFlagManager, starredOnly: Bool, studyObject: QLStudyObject, studySettings: [QLStudySetting]?, studySettingsService: StudySettingsService?, userDefaultsManager: UserDefaultsManager, userManager: QLUserManager, viewControllerFactory: QLViewControllerFactory) { | |
let roundGenerator = APIAssistantRoundGenerator(userManager: userManager, apiClient: QLAPIClient.sharedClient()) | |
self.init(audioManager: audioManager, featureFlagManager: featureFlagManager, starredOnly: starredOnly, studyObject: studyObject, roundGenerator: roundGenerator, studySettings: studySettings, studySettingsService: studySettingsService, userDefaultsManager: userDefaultsManager, userManager: userManager, viewControllerFactory: viewControllerFactory) | |
} | |
- init(audioManager: QLAudioManager, featureFlagManager: QLFeatureFlagManager, starredOnly: Bool, studyObject: QLStudyObject, roundGenerator: AssistantRoundGenerator, studySettings: [QLStudySetting]?, studySettingsService: StudySettingsService, userDefaultsManager: UserDefaultsManager, userManager: QLUserManager, viewControllerFactory: QLViewControllerFactory) { | |
+ init(audioManager: QLAudioManager, featureFlagManager: QLFeatureFlagManager, starredOnly: Bool, studyObject: QLStudyObject, roundGenerator: AssistantRoundGenerator, studySettings: [QLStudySetting]?, studySettingsService: StudySettingsService?, userDefaultsManager: UserDefaultsManager, userManager: QLUserManager, viewControllerFactory: QLViewControllerFactory) { | |
let termDataSource = QLAllTermDataSource(studyObject: studyObject, user: userManager.loggedInUser(), ordering: .Original, starredOnly: starredOnly, delegate: nil) | |
self.roundGenerator = roundGenerator | |
let dataManager = AssistantModeDataManager(termDataSource: termDataSource, userManager: userManager) | |
@@ -458,7 +465,7 @@ extension AssistantModeViewController: QLModeSettingsViewControllerDelegate { | |
options = AssistantOptions(promptTermSide: modeSettingsViewController.currentPromptTermSide, preferredQuestionTypes: preferredQuestionTypes) | |
if let user = userManager.loggedInUser() { | |
let studySettings = studySettingTransformer.studySettings(fromAssistantOptions: options, studyObject: studyObject, user: user) | |
- studySettingsService.saveStudySettings(studySettings) | |
+ studySettingsService?.saveStudySettings(studySettings) | |
} | |
} | |
} | |
diff --git a/Quizlet-iPhone/Components/ProfilePictureSettings/MoveAndScaleViewController.swift b/Quizlet-iPhone/Components/ProfilePictureSettings/MoveAndScaleViewController.swift | |
index 0b75f77..4794553 100644 | |
--- a/Quizlet-iPhone/Components/ProfilePictureSettings/MoveAndScaleViewController.swift | |
+++ b/Quizlet-iPhone/Components/ProfilePictureSettings/MoveAndScaleViewController.swift | |
@@ -174,12 +174,15 @@ class MoveAndScaleViewController: QLViewController { | |
var rect = CGRect.zero | |
rect.size = originalImage.size | |
originalImage.drawInRect(rect) | |
- upOrientedOriginalImage = UIGraphicsGetImageFromCurrentImageContext() | |
+ guard let imageFromContext = UIGraphicsGetImageFromCurrentImageContext() else { | |
+ fatalError("Cannot get image from current image context") | |
+ } | |
+ upOrientedOriginalImage = imageFromContext | |
UIGraphicsEndImageContext() | |
} | |
// Create cropped image by applying `cropRectInImageCoordinates` to `upOrientedOriginalImage` | |
- guard let croppedCGImage = CGImageCreateWithImageInRect(upOrientedOriginalImage.CGImage, cropRectInImageCoordinates) else { | |
+ guard let upOrientedOriginalCGImage = upOrientedOriginalImage.CGImage, croppedCGImage = CGImageCreateWithImageInRect(upOrientedOriginalCGImage, cropRectInImageCoordinates) else { | |
Assert(false, message: "Could not create cropped image: cropRectInImageCoordinates not within image") | |
return nil | |
} | |
diff --git a/Quizlet-iPhone/FlashcardsAutoPlayBackgroundTask.swift b/Quizlet-iPhone/FlashcardsAutoPlayBackgroundTask.swift | |
index ddf7cb3..073f39a 100644 | |
--- a/Quizlet-iPhone/FlashcardsAutoPlayBackgroundTask.swift | |
+++ b/Quizlet-iPhone/FlashcardsAutoPlayBackgroundTask.swift | |
@@ -148,7 +148,10 @@ class FlashcardsAutoPlayBackgroundTask: NSObject { | |
} | |
private func createEmptyPlayerItem() -> AVPlayerItem { | |
- let fillerEmptyAudioUrl = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("silence1point5sec.mp3") | |
+ let emptyAudioPath = "silence1point5sec.mp3" | |
+ guard let fillerEmptyAudioUrl = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent(emptyAudioPath) else { | |
+ fatalError("Cannot find file url for empty audio path: \(emptyAudioPath)") | |
+ } | |
let fillerEmptyAudioItem = AVPlayerItem(URL: fillerEmptyAudioUrl) | |
return fillerEmptyAudioItem | |
} | |
diff --git a/Quizlet-iPhone/ForceTouchShortcutsHandler.swift b/Quizlet-iPhone/ForceTouchShortcutsHandler.swift | |
index 0681856..b56b56b 100644 | |
--- a/Quizlet-iPhone/ForceTouchShortcutsHandler.swift | |
+++ b/Quizlet-iPhone/ForceTouchShortcutsHandler.swift | |
@@ -57,12 +57,12 @@ extension ForceTouchShortcutsHandler { | |
] | |
// add latest set if applicable | |
- if let set = mostRecentlyStudiedSet() { | |
+ if let set = mostRecentlyStudiedSet(), setIdString = set.objectID.URIRepresentation().absoluteString { | |
shortcuts.append( | |
UIMutableApplicationShortcutItem(type: ShortcutIdentifier.StudyLatest.rawValue, | |
localizedTitle: NSLocalizedString("QS_force_touch_action_recently_studied", comment: ""), localizedSubtitle: set.title, | |
icon: UIApplicationShortcutIcon(templateImageName: "quicklook-study-latest"), | |
- userInfo: [kQLObjectIDKeyPath: set.objectID.URIRepresentation().absoluteString] | |
+ userInfo: [kQLObjectIDKeyPath: setIdString] | |
) | |
) | |
} | |
diff --git a/Quizlet-iPhone/IntroViewController.swift b/Quizlet-iPhone/IntroViewController.swift | |
index ba5f6a1..7d50cca 100644 | |
--- a/Quizlet-iPhone/IntroViewController.swift | |
+++ b/Quizlet-iPhone/IntroViewController.swift | |
@@ -262,14 +262,15 @@ class IntroViewController: QLViewController { | |
let image = UIImage(named: usePortraitImage ? "Background" : "Background-Landscape")! | |
let imageAspectRatio = image.size.width / image.size.height | |
- var backgroundImage: UIImage | |
- | |
if (imageAspectRatio == viewAspectRatio) { | |
// If device is the same aspect ratio, just scale the image | |
UIGraphicsBeginImageContext(view.frame.size) | |
image.drawInRect(bounds) | |
- backgroundImage = UIGraphicsGetImageFromCurrentImageContext() | |
+ guard let backgroundImage = UIGraphicsGetImageFromCurrentImageContext() else { | |
+ fatalError("Cannot get image from current image context") | |
+ } | |
UIGraphicsEndImageContext() | |
+ return backgroundImage | |
} else { | |
// Scale the image | |
var rect: CGRect | |
@@ -284,13 +285,13 @@ class IntroViewController: QLViewController { | |
UIGraphicsBeginImageContext(rect.size) | |
image.drawInRect(rect) | |
- let tempImage = UIGraphicsGetImageFromCurrentImageContext() | |
+ guard let tempImage = UIGraphicsGetImageFromCurrentImageContext() else { | |
+ fatalError("Cannot get image from current image context") | |
+ } | |
UIGraphicsEndImageContext() | |
// Centers and crops the image | |
- backgroundImage = tempImage.QL_crop(toRect: CGRect(origin: origin, size: bounds.size)) | |
+ return tempImage.QL_crop(toRect: CGRect(origin: origin, size: bounds.size)) | |
} | |
- | |
- return backgroundImage | |
} | |
} | |
diff --git a/Quizlet-iPhone/JSONHelpers.swift b/Quizlet-iPhone/JSONHelpers.swift | |
new file mode 100644 | |
index 0000000..6ce28c3 | |
--- /dev/null | |
+++ b/Quizlet-iPhone/JSONHelpers.swift | |
@@ -0,0 +1,172 @@ | |
+// | |
+// Dictionary+JSON.swift | |
+// Quizlet | |
+// | |
+// Created by Jaclyn Chen on 10/13/16. | |
+// Copyright © 2016 Quizlet LLC. All rights reserved. | |
+// | |
+ | |
+typealias Payload = [String: AnyObject] | |
+ | |
+/*** Encode a payload (derived from: https://github.com/kylef/JSONWebToken.swift/releases/tag/1.5.0 minus the secure signature part) | |
+ currently used in tests for now but please move it to a separate target: https://github.com/quizlet/quizlet-ios/issues/5918 | |
+ - parameter payload: input payload dictionary | |
+ - returns: The JSON web token as a String | |
+ */ | |
+struct JSONEncoder { | |
+ func encode(payload: Payload) -> String { | |
+ func encodeJSON(payload: Payload) -> String? { | |
+ if let data = try? NSJSONSerialization.dataWithJSONObject(payload, options: NSJSONWritingOptions(rawValue: 0)) { | |
+ return base64encode(data) | |
+ } | |
+ return nil | |
+ } | |
+ | |
+ let header = encodeJSON(["typ": "JWT", "alg": "none"])! | |
+ let payload = encodeJSON(payload)! | |
+ let signingInput = "\(header).\(payload)" | |
+ let signature = "" | |
+ return "\(signingInput).\(signature)" | |
+ } | |
+ | |
+ /// URI Safe base64 encode | |
+ private func base64encode(input:NSData) -> String { | |
+ let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) | |
+ let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String | |
+ return string | |
+ .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ .stringByReplacingOccurrencesOfString("=", withString: "", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ } | |
+} | |
+ | |
+/*** Decode a payload string (derived from: https://github.com/kylef/JSONWebToken.swift/releases/tag/1.5.0) | |
+ - parameter payloadString: input payload string | |
+ - returns: Payload dictionary | |
+ */ | |
+struct JSONDecoder { | |
+ /// Failure reasons from decoding a JWT | |
+ enum InvalidToken : CustomStringConvertible, ErrorType { | |
+ /// Decoding the JWT itself failed | |
+ case DecodeError(String) | |
+ | |
+ /// The JWT uses an unsupported algorithm | |
+ case InvalidAlgorithm | |
+ | |
+ /// The issued claim has expired | |
+ case ExpiredSignature | |
+ | |
+ /// The issued claim is for the future | |
+ case ImmatureSignature | |
+ | |
+ /// The claim is for the future | |
+ case InvalidIssuedAt | |
+ | |
+ /// The audience of the claim doesn't match | |
+ case InvalidAudience | |
+ | |
+ /// The issuer claim failed to verify | |
+ case InvalidIssuer | |
+ | |
+ /// Returns a readable description of the error | |
+ var description: String { | |
+ switch self { | |
+ case .DecodeError(let error): | |
+ return "Decode Error: \(error)" | |
+ case .InvalidIssuer: | |
+ return "Invalid Issuer" | |
+ case .ExpiredSignature: | |
+ return "Expired Signature" | |
+ case .ImmatureSignature: | |
+ return "The token is not yet valid (not before claim)" | |
+ case .InvalidIssuedAt: | |
+ return "Issued at claim (iat) is in the future" | |
+ case InvalidAudience: | |
+ return "Invalid Audience" | |
+ case InvalidAlgorithm: | |
+ return "Unsupported algorithm or incorrect key" | |
+ } | |
+ } | |
+ } | |
+ | |
+ func decode(payloadString: String) throws -> Payload { | |
+ switch load(payloadString) { | |
+ case let .Success(_, payload, _, _): | |
+ return payload | |
+ case .Failure(let failure): | |
+ throw failure | |
+ } | |
+ } | |
+ | |
+ // MARK: Parsing a JWT | |
+ | |
+ enum LoadResult { | |
+ case Success(header:Payload, payload:Payload, signature:NSData, signatureInput:String) | |
+ case Failure(InvalidToken) | |
+ } | |
+ | |
+ func load(jwt:String) -> LoadResult { | |
+ let segments = jwt.componentsSeparatedByString(".") | |
+ if segments.count != 3 { | |
+ return .Failure(.DecodeError("Not enough segments")) | |
+ } | |
+ | |
+ let headerSegment = segments[0] | |
+ let payloadSegment = segments[1] | |
+ let signatureSegment = segments[2] | |
+ let signatureInput = "\(headerSegment).\(payloadSegment)" | |
+ | |
+ let headerData = base64decode(headerSegment) | |
+ if headerData == nil { | |
+ return .Failure(.DecodeError("Header is not correctly encoded as base64")) | |
+ } | |
+ | |
+ let header = (try? NSJSONSerialization.JSONObjectWithData(headerData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload | |
+ if header == nil { | |
+ return .Failure(.DecodeError("Invalid header")) | |
+ } | |
+ | |
+ let payloadData = base64decode(payloadSegment) | |
+ if payloadData == nil { | |
+ return .Failure(.DecodeError("Payload is not correctly encoded as base64")) | |
+ } | |
+ | |
+ let payload = (try? NSJSONSerialization.JSONObjectWithData(payloadData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload | |
+ if payload == nil { | |
+ return .Failure(.DecodeError("Invalid payload")) | |
+ } | |
+ | |
+ let signature = base64decode(signatureSegment) | |
+ if signature == nil { | |
+ return .Failure(.DecodeError("Signature is not correctly encoded as base64")) | |
+ } | |
+ | |
+ return .Success(header:header!, payload:payload!, signature:signature!, signatureInput:signatureInput) | |
+ } | |
+ | |
+ /// URI Safe base64 encode | |
+ private func base64encode(input:NSData) -> String { | |
+ let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) | |
+ let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String | |
+ return string | |
+ .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ .stringByReplacingOccurrencesOfString("=", withString: "", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ } | |
+ | |
+ /// URI Safe base64 decode | |
+ private func base64decode(input:String) -> NSData? { | |
+ let rem = input.characters.count % 4 | |
+ | |
+ var ending = "" | |
+ if rem > 0 { | |
+ let amount = 4 - rem | |
+ ending = String(count: amount, repeatedValue: Character("=")) | |
+ } | |
+ | |
+ let base64 = input.stringByReplacingOccurrencesOfString("-", withString: "+", options: NSStringCompareOptions(rawValue: 0), range: nil) | |
+ .stringByReplacingOccurrencesOfString("_", withString: "/", options: NSStringCompareOptions(rawValue: 0), range: nil) + ending | |
+ | |
+ return NSData(base64EncodedString: base64, options: NSDataBase64DecodingOptions(rawValue: 0)) | |
+ } | |
+} | |
diff --git a/Quizlet-iPhone/ModalAlertViewController.swift b/Quizlet-iPhone/ModalAlertViewController.swift | |
index 88eb16c..4de27a3 100644 | |
--- a/Quizlet-iPhone/ModalAlertViewController.swift | |
+++ b/Quizlet-iPhone/ModalAlertViewController.swift | |
@@ -357,11 +357,12 @@ class ModalAlertViewController: ModalBaseViewController, ModalAlertActionButtonD | |
// MARK: ModalAlertActionButtonDelegate | |
func modalAlertButtonPressed(button: ModalAlertActionButton) { | |
if button.alertStyle == .CancelAndDismissPresentingView || button.alertStyle == .DefaultAndDismissPresentingView { | |
- let modalSnapshot = modalContentView.snapshotViewAfterScreenUpdates(false) | |
view.alpha = 0.0 | |
- let presentingVC = self.presentingViewController | |
- presentingVC?.QL_addModalBase(Color.Indigo) | |
- presentingVC?.view.addSubview(modalSnapshot) | |
+ let presentingVC = presentingViewController | |
+ if let modalSnapshot = modalContentView.snapshotViewAfterScreenUpdates(false) { | |
+ presentingVC?.QL_addModalBase(Color.Indigo) | |
+ presentingVC?.view.addSubview(modalSnapshot) | |
+ } | |
self.dismissViewControllerAnimated(false, completion: { () -> Void in | |
presentingVC?.dismissViewControllerAnimated(true, completion: { () -> Void in | |
button.handler?(button) | |
diff --git a/Quizlet-iPhone/ModalDismissAnimator.swift b/Quizlet-iPhone/ModalDismissAnimator.swift | |
index 6faaa02..b2a8930 100644 | |
--- a/Quizlet-iPhone/ModalDismissAnimator.swift | |
+++ b/Quizlet-iPhone/ModalDismissAnimator.swift | |
@@ -15,7 +15,7 @@ class ModalDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning { | |
func animateTransition(transitionContext: UIViewControllerContextTransitioning) { | |
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! ModalBaseViewController! | |
- let containerView = transitionContext.containerView()! | |
+ let containerView = transitionContext.containerView() | |
let animationDuration = self.transitionDuration(transitionContext) | |
diff --git a/Quizlet-iPhone/ModalPresentationAnimator.swift b/Quizlet-iPhone/ModalPresentationAnimator.swift | |
index e2a6032..7b90a6a 100644 | |
--- a/Quizlet-iPhone/ModalPresentationAnimator.swift | |
+++ b/Quizlet-iPhone/ModalPresentationAnimator.swift | |
@@ -20,7 +20,7 @@ class ModalPresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning | |
let toView = toViewController.view | |
let fromView = fromViewController.view | |
- let containerView = transitionContext.containerView()! | |
+ let containerView = transitionContext.containerView() | |
let destinationRect = containerView.convertRect(fromView.bounds, fromView: fromView) | |
toView.frame = destinationRect | |
diff --git a/Quizlet-iPhone/ModalTransitionDelegate.swift b/Quizlet-iPhone/ModalTransitionDelegate.swift | |
index ba8ebcc..02e0052 100644 | |
--- a/Quizlet-iPhone/ModalTransitionDelegate.swift | |
+++ b/Quizlet-iPhone/ModalTransitionDelegate.swift | |
@@ -9,7 +9,7 @@ | |
import UIKit | |
class ModalTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate { | |
- func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? { | |
+ func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController?, sourceViewController source: UIViewController) -> UIPresentationController? { | |
let presentationController = ModalPresentationController(presentedViewController: presented, presentingViewController: source) | |
return presentationController; | |
} | |
diff --git a/Quizlet-iPhone/QLCreateSetViewController.m b/Quizlet-iPhone/QLCreateSetViewController.m | |
index 219cb89..4a017e3 100644 | |
--- a/Quizlet-iPhone/QLCreateSetViewController.m | |
+++ b/Quizlet-iPhone/QLCreateSetViewController.m | |
@@ -295,7 +295,9 @@ | |
} | |
}; | |
self.dataSource.termUnfocusedBlock = ^(QLTerm *term) { | |
- [weakSelf.context QL_save]; | |
+ dispatch_async(dispatch_get_main_queue(), ^{ | |
+ [weakSelf.context QL_save]; | |
+ }); | |
}; | |
self.dataSource.addTermAtEndBlock = ^() { | |
[weakSelf addTermAtEnd]; | |
diff --git a/Quizlet-iPhone/QLSetViewController.h b/Quizlet-iPhone/QLSetViewController.h | |
index f2a91d8..beedcca 100644 | |
--- a/Quizlet-iPhone/QLSetViewController.h | |
+++ b/Quizlet-iPhone/QLSetViewController.h | |
@@ -21,37 +21,37 @@ | |
@class QLSet; | |
@class QLTerm; | |
-typedef void(^QLSetDidBecomeNonNilBlock)(QLSetViewController *setViewController); | |
+typedef void(^QLSetDidBecomeNonNilBlock)(QLSetViewController * _Nonnull setViewController); | |
@interface QLSetViewController : QLDataViewController <UITextViewDelegate, QLSetPageTermsAdapterDelegate> | |
@property (nonatomic, assign) QLEmptyDataSetState emptyDataSetState; | |
-@property (copy, nonatomic) QLSetDidBecomeNonNilBlock setDidBecomeNonNilBlock; | |
- | |
-- (instancetype)initWithSet:(QLSet *)set | |
- audioManager:(QLAudioManager *)audioManager | |
- featureFlagManager:(QLFeatureFlagManager *)featureFlagManager | |
- permissions:(QLPermissions *)permissions | |
- syncEngine:(QLSyncEngine *)syncEngine | |
- testStudyModeConfigService:(id<TestStudyModeConfigService>)testStudyModeConfigService | |
- studySettingsService:(id<StudySettingsService>)studySettingsService | |
- userDefaultsManager:(UserDefaultsManager *)userDefaultsManager | |
- userManager:(QLUserManager *)userManager | |
- viewControllerFactory:(QLViewControllerFactory *)viewControllerFactory | |
- context:(NSManagedObjectContext *)context; | |
- | |
-- (instancetype)initWithSetId:(NSNumber *)setId | |
- audioManager:(QLAudioManager *)audioManager | |
- context:(NSManagedObjectContext *)context | |
- featureFlagManager:(QLFeatureFlagManager *)featureFlagManager | |
- permissions:(QLPermissions *)permissions | |
- syncEngine:(QLSyncEngine *)syncEngine | |
- testStudyModeConfigService:(id<TestStudyModeConfigService>)testStudyModeConfigService | |
- studySettingsService:(id<StudySettingsService>)studySettingsService | |
- userDefaultsManager:(UserDefaultsManager *)userDefaultsManager | |
- userManager:(QLUserManager *)userManager | |
- viewControllerFactory:(QLViewControllerFactory *)viewControllerFactory; | |
+@property (copy, nonatomic) QLSetDidBecomeNonNilBlock _Nullable setDidBecomeNonNilBlock; | |
+ | |
+- (instancetype _Nonnull)initWithSet:(QLSet * _Nonnull)set | |
+ audioManager:(QLAudioManager * _Nonnull)audioManager | |
+ featureFlagManager:(QLFeatureFlagManager * _Nonnull)featureFlagManager | |
+ permissions:(QLPermissions * _Nonnull)permissions | |
+ syncEngine:(QLSyncEngine * _Nonnull)syncEngine | |
+ testStudyModeConfigService:(id<TestStudyModeConfigService> _Nonnull)testStudyModeConfigService | |
+ studySettingsService:(id<StudySettingsService> _Nullable)studySettingsService | |
+ userDefaultsManager:(UserDefaultsManager * _Nonnull)userDefaultsManager | |
+ userManager:(QLUserManager * _Nonnull)userManager | |
+ viewControllerFactory:(QLViewControllerFactory * _Nonnull)viewControllerFactory | |
+ context:(NSManagedObjectContext * _Nonnull)context; | |
+ | |
+- (instancetype _Nonnull)initWithSetId:(NSNumber * _Nonnull)setId | |
+ audioManager:(QLAudioManager * _Nonnull)audioManager | |
+ context:(NSManagedObjectContext * _Nonnull)context | |
+ featureFlagManager:(QLFeatureFlagManager * _Nonnull)featureFlagManager | |
+ permissions:(QLPermissions * _Nonnull)permissions | |
+ syncEngine:(QLSyncEngine * _Nonnull)syncEngine | |
+ testStudyModeConfigService:(id<TestStudyModeConfigService> _Nonnull)testStudyModeConfigService | |
+ studySettingsService:(id<StudySettingsService> _Nullable)studySettingsService | |
+ userDefaultsManager:(UserDefaultsManager * _Nonnull)userDefaultsManager | |
+ userManager:(QLUserManager * _Nonnull)userManager | |
+ viewControllerFactory:(QLViewControllerFactory * _Nonnull)viewControllerFactory; | |
- (void)goToStudyMode:(QLStudyModeType)studyMode; | |
-- (void)setSet:(QLSet *)set; | |
+- (void)setSet:(QLSet * _Nonnull)set; | |
@end | |
diff --git a/Quizlet-iPhone/QLStudyObject+Helpers.swift b/Quizlet-iPhone/QLStudyObject+Helpers.swift | |
index 2d518f7..4945b78 100644 | |
--- a/Quizlet-iPhone/QLStudyObject+Helpers.swift | |
+++ b/Quizlet-iPhone/QLStudyObject+Helpers.swift | |
@@ -30,12 +30,12 @@ extension QLStudyObject { | |
extension QLStudyObject { | |
func QL_starCount(loggedInUser: QLUser?, context: NSManagedObjectContext) -> Int { | |
let fetchRequest = termsFetchRequestForUser(loggedInUser, starredOnly: true) | |
- var error: NSError? | |
- let count = context.countForFetchRequest(fetchRequest, error: &error) | |
- if let error = error { | |
- Assert(false, message: "Error returning results count: \(error.userInfo)") | |
+ do { | |
+ let count = try context.countForFetchRequest(fetchRequest) | |
+ return count | |
+ } catch let error { | |
+ Assert(false, message: "Error returning results count: \(error)") | |
return 0 | |
} | |
- return count | |
} | |
} | |
diff --git a/Quizlet-iPhone/QLViewControllerFactory.m b/Quizlet-iPhone/QLViewControllerFactory.m | |
index 64ddef1..1871f20 100644 | |
--- a/Quizlet-iPhone/QLViewControllerFactory.m | |
+++ b/Quizlet-iPhone/QLViewControllerFactory.m | |
@@ -326,13 +326,14 @@ | |
} | |
- (QLSetViewController *)setViewControllerWithSet:(QLSet *)set { | |
+ id<StudySettingsService> _Nullable studySettingsService = self.userManager.loggedInUser ? [[CoreDataStudySettingsService alloc] initWithUser:self.userManager.loggedInUser syncEngine:self.syncEngine context:self.defaultContext] : nil; | |
return [[QLSetViewController alloc] initWithSet:set | |
audioManager:self.audioManager | |
featureFlagManager:self.featureFlagManager | |
permissions:self.permissions | |
syncEngine:self.syncEngine | |
testStudyModeConfigService:[self testStudyModeConfigServiceForSessionWithContext:self.defaultContext] | |
- studySettingsService:[[CoreDataStudySettingsService alloc] initWithUser:self.userManager.loggedInUser syncEngine:self.syncEngine context:self.defaultContext] | |
+ studySettingsService:studySettingsService | |
userDefaultsManager:self.userDefaultsManager | |
userManager:self.userManager | |
viewControllerFactory:self | |
@@ -341,6 +342,7 @@ | |
} | |
- (QLSetViewController *)setViewControllerWithSetId:(NSNumber *)setId { | |
+ id<StudySettingsService> _Nullable studySettingsService = self.userManager.loggedInUser ? [[CoreDataStudySettingsService alloc] initWithUser:self.userManager.loggedInUser syncEngine:self.syncEngine context:self.defaultContext] : nil; | |
return [[QLSetViewController alloc] initWithSetId:setId | |
audioManager:self.audioManager | |
context:self.defaultContext | |
@@ -348,7 +350,7 @@ | |
permissions:self.permissions | |
syncEngine:self.syncEngine | |
testStudyModeConfigService:[self testStudyModeConfigServiceForSessionWithContext:self.defaultContext] | |
- studySettingsService:[[CoreDataStudySettingsService alloc] initWithUser:self.userManager.loggedInUser syncEngine:self.syncEngine context:self.defaultContext] | |
+ studySettingsService:studySettingsService | |
userDefaultsManager:self.userDefaultsManager | |
userManager:self.userManager | |
viewControllerFactory:self | |
diff --git a/Quizlet-iPhone/SearchOnboardingTransitioning.swift b/Quizlet-iPhone/SearchOnboardingTransitioning.swift | |
index cea9d57..c86753e 100644 | |
--- a/Quizlet-iPhone/SearchOnboardingTransitioning.swift | |
+++ b/Quizlet-iPhone/SearchOnboardingTransitioning.swift | |
@@ -29,8 +29,8 @@ class SearchOnboardingPresentationAnimator: NSObject, UIViewControllerAnimatedTr | |
} | |
func animateTransition(transitionContext: UIViewControllerContextTransitioning) { | |
- guard let container = transitionContext.containerView(), | |
- fromView = transitionContext.viewForKey(UITransitionContextFromViewKey), | |
+ let container = transitionContext.containerView() | |
+ guard let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey), | |
toView = transitionContext.viewForKey(UITransitionContextToViewKey) | |
else { | |
transitionContext.completeTransition(true) | |
diff --git a/Quizlet-iPhone/Services/ProfileImageServiceImplementation.swift b/Quizlet-iPhone/Services/ProfileImageServiceImplementation.swift | |
index 7fa97f1..072c95a 100644 | |
--- a/Quizlet-iPhone/Services/ProfileImageServiceImplementation.swift | |
+++ b/Quizlet-iPhone/Services/ProfileImageServiceImplementation.swift | |
@@ -166,7 +166,10 @@ class ProfileImageServiceImplementation: ProfileImageService { | |
if objectId.temporaryID { | |
fatalError("Cannot create a profile image object from non-temporary ID.") | |
} | |
- return ProfileImage(url: url, imageId: objectId.URIRepresentation().absoluteString) | |
+ guard let objectIdString = objectId.URIRepresentation().absoluteString else { | |
+ fatalError("Cannot get object Id string") | |
+ } | |
+ return ProfileImage(url: url, imageId: objectIdString) | |
} | |
/// Fetches the profile image model from core data corresponding to the ProfileImage. | |
diff --git a/Quizlet-iPhone/TestModeViewController.swift b/Quizlet-iPhone/TestModeViewController.swift | |
index c6a5c27..8935ccd 100644 | |
--- a/Quizlet-iPhone/TestModeViewController.swift | |
+++ b/Quizlet-iPhone/TestModeViewController.swift | |
@@ -19,7 +19,7 @@ class TestModeAnimator: NSObject, UIViewControllerAnimatedTransitioning { | |
let toView = toViewController.view | |
let fromView = fromViewController.view | |
- let containerView = transitionContext.containerView()! | |
+ let containerView = transitionContext.containerView() | |
let destinationRect = containerView.convertRect(fromView.bounds, fromView: fromView) | |
toView.frame = destinationRect | |
@@ -86,8 +86,11 @@ class TestModeTransitionContext : NSObject, UIViewControllerContextTransitioning | |
completionBlock?(didComplete) | |
} | |
- func containerView() -> UIView? { | |
- return _containerView | |
+ func containerView() -> UIView { | |
+ guard let containerView = _containerView else { | |
+ fatalError("Cannot get container view") | |
+ } | |
+ return containerView | |
} | |
func isAnimated() -> Bool { | |
@@ -117,6 +120,10 @@ class TestModeTransitionContext : NSObject, UIViewControllerContextTransitioning | |
func cancelInteractiveTransition() { | |
// no-op | |
} | |
+ | |
+ func pauseInteractiveTransition() { | |
+ // no-op | |
+ } | |
} | |
protocol ContainerViewController: class { | |
diff --git a/Quizlet-iPhone/TriangleView.swift b/Quizlet-iPhone/TriangleView.swift | |
index 94dc5c3..925e5f0 100644 | |
--- a/Quizlet-iPhone/TriangleView.swift | |
+++ b/Quizlet-iPhone/TriangleView.swift | |
@@ -21,15 +21,17 @@ class TriangleView: UIView { | |
} | |
override func drawRect(rect: CGRect) { | |
- let ctx = UIGraphicsGetCurrentContext() | |
+ guard let context = UIGraphicsGetCurrentContext() else { | |
+ return | |
+ } | |
- CGContextBeginPath(ctx) | |
- CGContextMoveToPoint(ctx, CGRectGetMidX(rect), CGRectGetMinY(rect)) // top middle | |
- CGContextAddLineToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect)) // bottom left | |
- CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect)) // bottom right | |
- CGContextClosePath(ctx) | |
+ CGContextBeginPath(context) | |
+ CGContextMoveToPoint(context, CGRectGetMidX(rect), CGRectGetMinY(rect)) // top middle | |
+ CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect)) // bottom left | |
+ CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect)) // bottom right | |
+ CGContextClosePath(context) | |
- CGContextSetFillColorWithColor(ctx, color.CGColor) | |
- CGContextFillPath(ctx) | |
+ CGContextSetFillColorWithColor(context, color.CGColor) | |
+ CGContextFillPath(context) | |
} | |
} | |
diff --git a/Quizlet-iPhone/UIImage+Color.swift b/Quizlet-iPhone/UIImage+Color.swift | |
index 101f438..72a6006 100644 | |
--- a/Quizlet-iPhone/UIImage+Color.swift | |
+++ b/Quizlet-iPhone/UIImage+Color.swift | |
@@ -11,24 +11,35 @@ import UIKit | |
extension UIImage { | |
func QL_tintedWithLinearGradient(startColor: UIColor, endColor: UIColor, transitionPoint: CGPoint) -> UIImage { | |
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale); | |
- let context = UIGraphicsGetCurrentContext() | |
+ guard let context = UIGraphicsGetCurrentContext() else { | |
+ fatalError("Cannot get current context") | |
+ } | |
CGContextTranslateCTM(context, 0, self.size.height) | |
CGContextScaleCTM(context, 1.0, -1.0) | |
CGContextSetBlendMode(context, CGBlendMode.Normal) | |
let rect = CGRectMake(0, 0, self.size.width, self.size.height) | |
- CGContextClipToMask(context, rect, self.CGImage) | |
+ guard let CGImage = CGImage else { | |
+ fatalError("Cannot get CGImage") | |
+ } | |
+ CGContextClipToMask(context, rect, CGImage) | |
var colors = [startColor.CGColor, startColor.CGColor] as CFArray | |
let space = CGColorSpaceCreateDeviceRGB() | |
- var gradient = CGGradientCreateWithColors(space, colors, nil) | |
- CGContextDrawLinearGradient(context, gradient, CGPointMake(0, self.size.height), transitionPoint, CGGradientDrawingOptions.DrawsBeforeStartLocation) | |
+ guard let startGradient = CGGradientCreateWithColors(space, colors, nil) else { | |
+ fatalError("Cannot get gradient with\nspace: \(space)\ncolors: \(colors)") | |
+ } | |
+ CGContextDrawLinearGradient(context, startGradient, CGPointMake(0, self.size.height), transitionPoint, CGGradientDrawingOptions.DrawsBeforeStartLocation) | |
colors = [startColor.CGColor, endColor.CGColor] as CFArray | |
- gradient = CGGradientCreateWithColors(space, colors, nil) | |
- CGContextDrawLinearGradient(context, gradient, transitionPoint, CGPointMake(0, 0), CGGradientDrawingOptions.DrawsBeforeStartLocation) | |
+ guard let endGradient = CGGradientCreateWithColors(space, colors, nil) else { | |
+ fatalError("Cannot get gradient with\nspace: \(space)\ncolors: \(colors)") | |
+ } | |
+ CGContextDrawLinearGradient(context, endGradient, transitionPoint, CGPointMake(0, 0), CGGradientDrawingOptions.DrawsBeforeStartLocation) | |
- let gradientImage = UIGraphicsGetImageFromCurrentImageContext() | |
+ guard let gradientImage = UIGraphicsGetImageFromCurrentImageContext() else { | |
+ fatalError("Cannot get image from current image context") | |
+ } | |
UIGraphicsEndImageContext() | |
return gradientImage | |
@@ -37,19 +48,25 @@ extension UIImage { | |
func QL_tintedWithColor(color: UIColor) -> UIImage { | |
let rect = CGRectMake(0, 0, self.size.width, self.size.height) | |
UIGraphicsBeginImageContext(rect.size) | |
- let context = UIGraphicsGetCurrentContext() | |
+ | |
+ guard let context = UIGraphicsGetCurrentContext() else { | |
+ fatalError("Cannot get current context") | |
+ } | |
+ guard let CGImage = CGImage else { | |
+ fatalError("Cannot get CGImage") | |
+ } | |
- CGContextClipToMask(context, rect, self.CGImage) | |
+ CGContextClipToMask(context, rect, CGImage) | |
CGContextSetFillColorWithColor(context, color.CGColor) | |
CGContextFillRect(context, rect) | |
let image = UIGraphicsGetImageFromCurrentImageContext() | |
UIGraphicsEndImageContext() | |
- if let cgImage = image.CGImage { | |
+ if let cgImage = image?.CGImage { | |
let flippedImage = UIImage(CGImage: cgImage, scale: 1.0, orientation: UIImageOrientation.DownMirrored) | |
return flippedImage | |
} | |
return self | |
} | |
-} | |
\ No newline at end of file | |
+} | |
diff --git a/Quizlet-iPhone/UIImage+Size.swift b/Quizlet-iPhone/UIImage+Size.swift | |
index e4629ff..aa1656f 100644 | |
--- a/Quizlet-iPhone/UIImage+Size.swift | |
+++ b/Quizlet-iPhone/UIImage+Size.swift | |
@@ -11,7 +11,10 @@ import UIKit | |
extension UIImage { | |
func QL_crop(toRect rect: CGRect) -> UIImage { | |
let scaledRect = CGRectMake(rect.origin.x * self.scale, rect.origin.y * self.scale, rect.size.width * self.scale, rect.size.height * self.scale) | |
- if let imageRef = CGImageCreateWithImageInRect(self.CGImage, scaledRect) { | |
+ guard let CGImage = CGImage else { | |
+ fatalError("Cannot get CGImage") | |
+ } | |
+ if let imageRef = CGImageCreateWithImageInRect(CGImage, scaledRect) { | |
let image = UIImage(CGImage: imageRef, scale: self.scale, orientation: self.imageOrientation) | |
return image | |
} | |
@@ -20,7 +23,7 @@ extension UIImage { | |
} | |
} | |
- func QL_scale(let scale: CGFloat) -> UIImage { | |
+ func QL_scale(scale: CGFloat) -> UIImage { | |
if scale == 1.0 { | |
return self | |
} | |
@@ -30,7 +33,9 @@ extension UIImage { | |
UIGraphicsBeginImageContext(newSize); | |
UIGraphicsBeginImageContextWithOptions(newSize, false, screenScale); | |
drawInRect(CGRectMake(0,0,newSize.width,newSize.height)) | |
- let newImage = UIGraphicsGetImageFromCurrentImageContext() | |
+ guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else { | |
+ fatalError("Cannot get image from current image context") | |
+ } | |
UIGraphicsEndImageContext() | |
return newImage | |
} | |
diff --git a/Quizlet-iPhone/UniversalLinkHandler.swift b/Quizlet-iPhone/UniversalLinkHandler.swift | |
index 9f6daab..bce7e87 100644 | |
--- a/Quizlet-iPhone/UniversalLinkHandler.swift | |
+++ b/Quizlet-iPhone/UniversalLinkHandler.swift | |
@@ -8,7 +8,6 @@ | |
import UIKit | |
import RxSwift | |
-import JWT | |
/// Struct for universal link Rx result. | |
struct ModelUniversalLinkMultiResult { | |
@@ -39,9 +38,9 @@ struct EmailTrackingData { | |
if !queryValue.hasSuffix(".") { | |
queryValue = queryValue + "." | |
} | |
- | |
+ | |
do { | |
- let payload = try JWT.decode(queryValue, algorithm: .None) | |
+ let payload = try JSONDecoder().decode(queryValue) | |
guard let email = payload[EmailTrackingData.EmailKey] as? String else { | |
return nil | |
} | |
diff --git a/Quizlet-iPhone/libraries/KIF b/Quizlet-iPhone/libraries/KIF | |
index dc3adab..de6995b 160000 | |
--- a/Quizlet-iPhone/libraries/KIF | |
+++ b/Quizlet-iPhone/libraries/KIF | |
@@ -1 +1 @@ | |
-Subproject commit dc3adabcb94ec0ac5db45bd420cba9ac2a634c3f | |
+Subproject commit de6995b0f6d840b89194f9f978b18ae68e33edf9 | |
diff --git a/Quizlet-iPhone/libraries/quizlet-shared-config b/Quizlet-iPhone/libraries/quizlet-shared-config | |
index 421f81b..96f0b53 160000 | |
--- a/Quizlet-iPhone/libraries/quizlet-shared-config | |
+++ b/Quizlet-iPhone/libraries/quizlet-shared-config | |
@@ -1 +1 @@ | |
-Subproject commit 421f81b0ce40f7bd1e7aa261681ef815fedeeb63 | |
+Subproject commit 96f0b536371f39ee51363b7393b4bbcc0ec5f0ba |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment