Skip to content

Instantly share code, notes, and snippets.

@jaclync
Last active October 17, 2016 21:29
Show Gist options
  • Save jaclync/15fd3a69bee084237a07084bb6c43bcc to your computer and use it in GitHub Desktop.
Save jaclync/15fd3a69bee084237a07084bb6c43bcc to your computer and use it in GitHub Desktop.
jaclyn/swift2.3..develop.diff
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