Advertisement
Guest User

Untitled

a guest
May 30th, 2016
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.44 KB | None | 0 0
  1. //
  2. // BaseViewController.swift
  3. // LushApp
  4. //
  5. // Created by Shagun Madhikarmi on 06/10/2014.
  6. // Copyright (c) 2014 Lush. All rights reserved.
  7. //
  8. import UIKit
  9. import ReachabilitySwift
  10. import Crashlytics
  11.  
  12. class BaseViewController: GAITrackedViewController {
  13.  
  14. private(set) var loadingView: LoadingView?
  15. var refreshControl: UIRefreshControl?
  16. var reachability: Reachability? = nil
  17. var errorView: ErrorView?
  18. var basketViewController: BasketViewController?
  19. var themeStyle: ThemeStyle {
  20.  
  21. get {
  22. return .Light
  23. }
  24. }
  25.  
  26. var showNavigationBar: Bool {
  27.  
  28. get {
  29.  
  30. return true
  31. }
  32. }
  33.  
  34. var appDelegate: AppDelegate {
  35.  
  36. get {
  37.  
  38. return UIApplication.sharedApplication().delegate as! AppDelegate
  39. }
  40. }
  41.  
  42. var online: Bool = false
  43. var wifiConnection: Bool = true
  44.  
  45.  
  46. // MARK: - View lifecycle
  47.  
  48. override func viewDidLoad() {
  49.  
  50. super.viewDidLoad()
  51.  
  52. self.setupUserInterface()
  53. }
  54.  
  55. override func viewWillAppear(animated: Bool) {
  56.  
  57. super.viewWillAppear(animated)
  58.  
  59. self.addBasketNotificationObservers()
  60. self.addSlideNotificationObservers()
  61. self.addSessionExpiredNotificationObservers()
  62. self.addSessionLoginNotificationObservers()
  63. self.updateTheme()
  64. self.updateBasketCounter(animated: false)
  65. }
  66.  
  67. override func viewDidAppear(animated: Bool) {
  68.  
  69. super.viewDidAppear(animated)
  70.  
  71. // Sets first element to be read by voice over only if navigation bar not hidden
  72.  
  73. if let titleView = self.navigationItem.titleView {
  74.  
  75. self.navigationController?.setupAccessibilityDefaultItem(titleView)
  76. }
  77. }
  78.  
  79. override func viewWillDisappear(animated: Bool) {
  80.  
  81. super.viewWillDisappear(animated)
  82.  
  83. self.removeBasketNotificationObservers()
  84. self.removeSlideNotificationObservers()
  85. self.removeSessionExpiredNotificationObservers()
  86. self.removeSessionLoginNotificationObservers()
  87.  
  88. BasketManager.sharedInstance.cancelNetworkRequests()
  89. ImageProxy.sharedInstance.cancelNetworkRequests()
  90.  
  91. if let reachability = self.reachability {
  92.  
  93. reachability.stopNotifier()
  94. reachability.whenReachable = nil
  95. reachability.whenUnreachable = nil
  96. }
  97. self.reachability = nil
  98. }
  99.  
  100.  
  101. // MARK: - User Interface
  102.  
  103. func setupUserInterface() {
  104.  
  105. self.setupNavigationBar()
  106. }
  107.  
  108. func setupReachabilityNotifier() {
  109.  
  110. // Setup Reachability Notification only if needed
  111.  
  112. if self.reachability == nil {
  113.  
  114. self.reachability = try? Reachability.reachabilityForInternetConnection()
  115.  
  116. self.reachability?.whenReachable = { reachability in
  117. if reachability.isReachableViaWiFi() {
  118.  
  119. self.wifiConnection = true
  120. } else {
  121.  
  122. self.wifiConnection = false
  123. }
  124. self.online = true
  125. }
  126. self.reachability?.whenUnreachable = { reachability in
  127.  
  128. self.online = false
  129. }
  130.  
  131. do {
  132.  
  133. try self.reachability?.startNotifier()
  134.  
  135. //
  136. if let wifiResult = self.reachability?.isReachableViaWiFi() {
  137.  
  138. self.wifiConnection = wifiResult
  139. } else {
  140.  
  141. self.wifiConnection = false
  142. }
  143.  
  144. if let onlineResult = self.reachability?.isReachable() {
  145.  
  146. self.online = onlineResult
  147. } else {
  148.  
  149. self.online = false
  150. }
  151. } catch {
  152.  
  153. self.wifiConnection = false
  154. self.online = false
  155. }
  156.  
  157. }
  158. }
  159.  
  160. func updateUserInterface() {
  161.  
  162. self.hideLoadingView()
  163. }
  164.  
  165. func loadDataAndUpdateUserInterface() {
  166.  
  167. self.hideErrorView()
  168.  
  169. if let refreshControl = self.refreshControl where refreshControl.refreshing {
  170.  
  171. self.hideLoadingView()
  172.  
  173. } else {
  174.  
  175. self.showLoadingView()
  176. }
  177. }
  178.  
  179.  
  180. // MARK: - Theme
  181.  
  182. func updateTheme() {
  183.  
  184. if (self.showNavigationBar) {
  185.  
  186. ThemeManager.sharedInstance.setThemeStyle(self.themeStyle, viewController: self, animated: true)
  187.  
  188. } else {
  189.  
  190. ThemeManager.sharedInstance.setThemeStyle(self.themeStyle)
  191. }
  192.  
  193. self.showOrHideNavigationBar(animated: true)
  194. }
  195.  
  196.  
  197. // MARK: - Notifications
  198.  
  199. private func addBasketNotificationObservers() {
  200.  
  201. NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(BaseViewController.basketUpdated(_:)), name: kBasketManagerBasketUpdatedNotification, object: nil)
  202. }
  203.  
  204. private func addSlideNotificationObservers() {
  205.  
  206. if (self.showNavigationBar) {
  207.  
  208. NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(BaseViewController.slideMenuWillClose(_:)), name: kSlideMenuWillCloseNotification, object: nil)
  209. }
  210. }
  211.  
  212. private func removeBasketNotificationObservers() {
  213.  
  214. NSNotificationCenter.defaultCenter().removeObserver(self, name: kBasketManagerBasketUpdatedNotification, object: nil)
  215. }
  216.  
  217. private func removeSlideNotificationObservers() {
  218.  
  219. NSNotificationCenter.defaultCenter().removeObserver(self, name: kSlideMenuWillCloseNotification, object: nil)
  220. }
  221.  
  222. func slideMenuWillClose(notification: NSNotification) {
  223.  
  224. self.updateTheme()
  225.  
  226. // Re enable swipe to pop back
  227.  
  228. self.enablePopGesture(true)
  229. }
  230.  
  231. func basketUpdated(notification: NSNotification) {
  232.  
  233. self.updateBasketCounter(animated: true)
  234. }
  235.  
  236.  
  237. // MARK: - User Session
  238.  
  239. func addSessionLoginNotificationObservers() {
  240.  
  241. NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(BaseViewController.sessionLoggedIn(_:)), name: kSessionManagerSessionLoggedIn, object: nil)
  242. }
  243.  
  244. func removeSessionLoginNotificationObservers() {
  245.  
  246. NSNotificationCenter.defaultCenter().removeObserver(self, name: kSessionManagerSessionLoggedIn, object: nil)
  247. }
  248.  
  249. func addSessionExpiredNotificationObservers() {
  250.  
  251. // Abstract Method: Implement if necessary
  252. }
  253.  
  254. func removeSessionExpiredNotificationObservers() {
  255.  
  256. // Abstract Method: Implement if necessary
  257. }
  258.  
  259. func sessionExpired(notification: NSNotification) {
  260.  
  261. // Call this when wanting to notify the user of session expired
  262.  
  263. self.showUserSessionTimeoutAlert()
  264. }
  265.  
  266. func sessionLoggedIn(notification: NSNotification) {
  267.  
  268. // Abstract Method: Implement if necessary
  269. }
  270.  
  271. func refreshUserSession() {
  272.  
  273. if SessionManager.sharedInstance.isUserLoggedIn {
  274.  
  275. SessionManager.sharedInstance.refreshSessionIfNeeded({ () -> () in
  276.  
  277. }, failure: { (error) -> () in
  278.  
  279. })
  280. }
  281. }
  282.  
  283.  
  284. // MARK: - Navigation Bar
  285.  
  286. private func setupNavigationBar() {
  287.  
  288. if let navigationController = self.navigationController {
  289.  
  290. if (navigationController.viewControllers.count > 1) {
  291.  
  292. // Setting navigation bar back button
  293.  
  294. let backBarButtonItem: UIBarButtonItem = UIBarButtonItem.backBarButtonItem()
  295.  
  296. if let backBarButton = backBarButtonItem.customView as? UIButton {
  297.  
  298. backBarButton.addTarget(self, action: #selector(BaseViewController.didPressBackBarButtonItem(_:)), forControlEvents: .TouchUpInside)
  299. }
  300.  
  301. if let screenTitle = self.navigationController?.previousToTopViewControllerTitle() {
  302.  
  303. backBarButtonItem.accessibilityLabel = String.localizedString("BACK_BUTTON_ACCESSIBILITY_LABEL", comment: "") + screenTitle
  304. }
  305.  
  306. self.navigationItem.leftBarButtonItem = backBarButtonItem
  307. }
  308.  
  309. // Setting navigation bar basket button
  310.  
  311. let basketBarButtonItem: UIBarButtonItem = UIBarButtonItem.basketBarButtonItem()
  312.  
  313. if let basketBarButton = basketBarButtonItem.customView as? BadgeButtonControl {
  314.  
  315. let basketCounter: Int = BasketManager.sharedInstance.numberOfItemsInBasket()
  316. basketBarButton.setBadgeCounter(basketCounter, animated: false)
  317. basketBarButton.addTarget(self, action: #selector(BaseViewController.didPressBasketBarButtonItem(_:)), forControlEvents: .TouchUpInside)
  318. }
  319.  
  320. self.navigationItem.rightBarButtonItem = basketBarButtonItem
  321. }
  322. }
  323.  
  324. func showOrHideNavigationBar(animated animated: Bool = true) {
  325.  
  326. self.showOrHideNavigationBar(self.showNavigationBar, animated: animated)
  327. }
  328.  
  329. private func showOrHideNavigationBar(visible: Bool, animated: Bool = true) {
  330.  
  331. if let navigationController = self.navigationController {
  332.  
  333. let duration: NSTimeInterval = (animated) ? 0.275 : 0.0
  334.  
  335. UIView.animateWithDuration(duration, animations: { () -> Void in
  336.  
  337. navigationController.navigationBar.hidden = !visible
  338. })
  339. }
  340. }
  341.  
  342.  
  343. // MARK: - Back Button
  344.  
  345. func didPressBackBarButtonItem(sender: UIBarButtonItem) {
  346.  
  347. if let navigationController = self.navigationController {
  348.  
  349. navigationController.popViewControllerAnimated(true)
  350. }
  351. }
  352.  
  353.  
  354. // MARK: - Basket Button
  355.  
  356. private func updateBasketCounter(animated animated: Bool) {
  357.  
  358. let basketBarButtonItem: UIBarButtonItem? = self.navigationItem.rightBarButtonItem
  359.  
  360. if let basketBarButton = basketBarButtonItem?.customView as? BadgeButtonControl {
  361.  
  362. let basketCounter: Int = BasketManager.sharedInstance.numberOfItemsInBasket()
  363. basketBarButton.setBadgeCounter(basketCounter, animated: animated)
  364. }
  365. }
  366.  
  367. func showNavigationBarBasketButtonItem() {
  368.  
  369. self.showOrHideNavigationBarBasketButtonItem(true)
  370. }
  371.  
  372. func hideNavigationBarBasketButtonItem() {
  373.  
  374. self.showOrHideNavigationBarBasketButtonItem(false)
  375. }
  376.  
  377. func showOrHideNavigationBarBasketButtonItem(visible: Bool, animated: Bool = true) {
  378.  
  379. if (self.navigationController != nil) {
  380. self.navigationItem.rightBarButtonItem = nil
  381. self.navigationController!.navigationItem.rightBarButtonItem = nil
  382.  
  383. if visible {
  384. // Setting navigation bar basket button
  385.  
  386. let basketBarButtonItem: UIBarButtonItem = UIBarButtonItem.basketBarButtonItem()
  387.  
  388. if let basketBarButton = basketBarButtonItem.customView as? BadgeButtonControl {
  389.  
  390. basketBarButton.addTarget(self, action: #selector(BaseViewController.didPressBasketBarButtonItem(_:)), forControlEvents: .TouchUpInside)
  391. basketBarButton.image = ThemeManager.sharedInstance.theme!.basketButtonImage()
  392. basketBarButton.highlightedImage = ThemeManager.sharedInstance.theme!.basketButtonHighlightedImage()
  393. let basketCounter: Int = BasketManager.sharedInstance.numberOfItemsInBasket()
  394. basketBarButton.setBadgeCounter(basketCounter, animated: animated)
  395. }
  396.  
  397. self.navigationItem.rightBarButtonItem = basketBarButtonItem
  398. self.navigationController!.navigationItem.rightBarButtonItem = basketBarButtonItem
  399.  
  400. } else {
  401.  
  402. self.navigationItem.rightBarButtonItem = nil
  403. self.navigationController!.navigationItem.rightBarButtonItem = nil
  404. }
  405. }
  406. }
  407.  
  408. func didPressBasketBarButtonItem(sender: UIBarButtonItem) {
  409.  
  410. // End Editing
  411.  
  412. self.view.endEditing(true)
  413.  
  414. // Disable swype to pop back
  415.  
  416. self.enablePopGesture(false)
  417.  
  418. // Lazy load / Open Basket [We must make sure that the Basket View Controller is kept in memory or else UIAlertViewDelegate callback causes app to crash]
  419.  
  420. if self.basketViewController == nil {
  421.  
  422. self.basketViewController = BasketViewController()
  423. }
  424.  
  425. if let slideMenuViewController = self.slideMenuViewController(), let basketViewController = self.basketViewController {
  426.  
  427. slideMenuViewController.openRightViewController(basketViewController)
  428. }
  429. }
  430.  
  431.  
  432. // MARK: - Error handling
  433.  
  434. func handleError(error: NSError?) {
  435.  
  436. let message: String = NSError.localizedMessage(error)
  437. self.showErrorWithMessage(message)
  438. }
  439.  
  440. func showErrorWithMessage(message: String) {
  441.  
  442. let title: String = String.localizedString("COMMON_ERROR_TITLE", comment: "")
  443. self.showErrorWithMessage(title: title, message: message)
  444. }
  445.  
  446. func showErrorWithMessage(title title: String, message: String) {
  447.  
  448. // If there's a loading view hide that first
  449.  
  450. self.hideLoadingView()
  451. self.hideErrorView()
  452.  
  453. // Create view
  454.  
  455. self.errorView = ErrorView(frame: CGRectZero)
  456. self.view.addSubview(self.errorView!)
  457.  
  458. // layout
  459.  
  460. self.errorView?.translatesAutoresizingMaskIntoConstraints = false
  461.  
  462. self.errorView?.addCenterXConstraint(toView: self.errorView?.superview)
  463. self.errorView?.addCenterYConstraint(toView: self.errorView?.superview)
  464. self.errorView?.addLeftConstraint(toView: self.errorView?.superview, relation: .Equal, constant: 0)
  465. self.errorView?.addRightConstraint(toView: self.errorView?.superview, relation: .Equal, constant: 0)
  466. self.errorView?.addBottomConstraint(toView: self.errorView?.superview, attribute: .Bottom, relation: .LessThanOrEqual, constant: 0)
  467.  
  468. // content
  469. self.errorView?.setTitle(title, subtitle: message)
  470.  
  471. // accessibility
  472. self.errorView?.accessibilityIdentifier = AccessibilityHelper.accessibilityIdentifierWithPrefix("COMMON_ERROR", suffixes: ["MESSAGE"])
  473.  
  474. if (kDEBUG) {
  475.  
  476. self.errorView!.backgroundColor = UIColor.orangeColor()
  477. }
  478. }
  479.  
  480. func hideErrorView() {
  481.  
  482. self.errorView?.removeFromSuperview()
  483. self.errorView = nil
  484. }
  485.  
  486.  
  487. // MARK: - Order Exceptions
  488.  
  489. func getErrorAlertTitleAndMessageFromUpdateOrder(order: Order?, error: NSError?) -> (String, String)? {
  490.  
  491. var alertTitleAndMessage: (String, String)?
  492.  
  493. let basketManager: BasketManager = BasketManager.sharedInstance
  494.  
  495. let basketItems: [BasketItem] = basketManager.getBasketItems()
  496. let previousBasketItems: [BasketItem] = basketManager.previousBasketItems
  497.  
  498. var title: String?
  499. var message: String?
  500.  
  501. if let updatedOrder = order where updatedOrder.hasOrderExceptions {
  502.  
  503. // Note. since we have detected exceptions find the appropriate messsage
  504.  
  505. if (previousBasketItems.count > basketItems.count) {
  506.  
  507. let productVariantTitles = ProductVariant.joinedProductVariantTitles(updatedOrder.exceptionProductVariants)
  508.  
  509. message = NSString(format: String.localizedString("COMMON_ERROR_EXCEPTION_PRODUCTS_REMOVED", comment: ""), productVariantTitles) as String
  510. title = String.localizedString("COMMON_ERROR_EXCEPTION_PRODUCTS_REMOVED_ALERT_TITLE", comment: "")
  511.  
  512. } else if (basketManager.numberOfItemsPreviouslyInBasket() > basketManager.numberOfItemsInBasket()) {
  513.  
  514. message = String.localizedString("COMMON_ERROR_EXCEPTION_PRODUCTS_UPDATED", comment: "")
  515. title = String.localizedString("COMMON_ERROR_EXCEPTION_PRODUCTS_UPDATED_ALERT_TITLE", comment: "")
  516.  
  517. } else {
  518.  
  519. message = String.localizedString("COMMON_ERROR_MESSAGE_UPDATE_ORDER", comment: "")
  520. title = String.localizedString("COMMON_ERROR_TITLE", comment: "")
  521. }
  522.  
  523. } else if let serverError = error {
  524.  
  525. if (serverError.isNotAvailableError()) {
  526.  
  527. message = String.localizedString("COMMON_ERROR_NO_AVAILABLE_LINE_ITEMS", comment: "")
  528. title = String.localizedString("COMMON_ERROR_NO_AVAILABLE_LINE_ITEMS_ALERT_TITLE", comment: "")
  529.  
  530. } else if (serverError.domain == kErrorDomain && (serverError.code == ErrorCode.CreateOrder.rawValue)) {
  531.  
  532. message = String.localizedString("COMMON_ERROR_MESSAGE_CREATE_ORDER", comment: "")
  533. title = String.localizedString("COMMON_ERROR_TITLE", comment: "")
  534.  
  535. } else if (serverError.domain == kErrorDomain && (serverError.code == ErrorCode.UpdateOrder.rawValue)) {
  536.  
  537. message = String.localizedString("COMMON_ERROR_MESSAGE_UPDATE_ORDER", comment: "")
  538. title = String.localizedString("COMMON_ERROR_TITLE", comment: "")
  539.  
  540. } else {
  541.  
  542. message = String.localizedString("COMMON_ERROR_MESSAGE_UPDATE_ORDER", comment: "")
  543. title = String.localizedString("COMMON_ERROR_TITLE", comment: "")
  544. }
  545. }
  546.  
  547. if let alertMessage = message, let alertTitle = title {
  548.  
  549. alertTitleAndMessage = (alertTitle, alertMessage)
  550. }
  551.  
  552. return alertTitleAndMessage
  553. }
  554.  
  555. func showUpdateOrderAlertControllerIfNecessary(order: Order?, error: NSError?, completion: () -> ()) {
  556.  
  557. if let alertTitleAndMessage = self.getErrorAlertTitleAndMessageFromUpdateOrder(order, error: error) {
  558.  
  559. let title: String = alertTitleAndMessage.0
  560. let message: String = alertTitleAndMessage.1
  561.  
  562. self.showUpdateOrderAlertController(title, message: message, completion: completion)
  563.  
  564. } else {
  565.  
  566. completion()
  567. }
  568. }
  569.  
  570. func showUpdateOrderAlertController(title: String, message: String, completion: (() -> ())) {
  571.  
  572. let alertController: UIAlertController = UIAlertController(title: title, message: message as String, preferredStyle: .Alert)
  573.  
  574. let okAction: UIAlertAction = UIAlertAction(title: String.localizedString("OK", comment: ""), style: .Default, handler: { (alertAction) -> Void in
  575.  
  576. let basketItems = BasketManager.sharedInstance.getBasketItems()
  577.  
  578. if (basketItems.isEmpty) {
  579.  
  580. BasketManager.sharedInstance.order?.restoreDefaultValues()
  581.  
  582. self.navigationController?.dismissViewControllerAnimated(true, completion: { () -> Void in
  583.  
  584. completion()
  585. })
  586.  
  587. } else {
  588.  
  589. completion()
  590. }
  591. })
  592.  
  593. alertController.addAction(okAction)
  594.  
  595. self.presentViewController(alertController, animated: true, completion: nil)
  596.  
  597. }
  598.  
  599.  
  600. // MARK: - Navigation Controller methods
  601.  
  602. func fadeInAndAnimateToBack() -> () {
  603.  
  604. UIView.animateWithDuration(
  605. kFadeAnimationDuration,
  606. delay: 0,
  607. options: .CurveEaseIn,
  608. animations: {
  609.  
  610. self.view.alpha = 1
  611.  
  612. }, completion: nil)
  613. }
  614.  
  615. func searchNavigationController()-> SearchNavigationController? {
  616.  
  617. var searchNavigationController: SearchNavigationController? = nil
  618.  
  619. if (self.navigationController != nil) {
  620.  
  621. if (self.navigationController!.dynamicType === SearchNavigationController.self) {
  622.  
  623. searchNavigationController = self.navigationController as? SearchNavigationController
  624. }
  625. }
  626.  
  627. return searchNavigationController
  628. }
  629.  
  630.  
  631. // MARK: - Loading
  632.  
  633. func showLoadingView() {
  634.  
  635. if self.loadingView != nil {
  636.  
  637. self.hideLoadingView()
  638. }
  639.  
  640. // Create view
  641.  
  642. self.loadingView = LoadingView(frame: CGRectZero)
  643. self.view.addSubview(self.loadingView! )
  644.  
  645. self.loadingView?.translatesAutoresizingMaskIntoConstraints = false
  646. self.loadingView?.fillSuperView(UIEdgeInsetsZero)
  647.  
  648. self.loadingView?.startAnimating()
  649. }
  650.  
  651. func showLoadingViewWithBackground() {
  652.  
  653. self.showLoadingView()
  654. self.loadingView?.backgroundColor = UIColor.lightBackgroundColor()
  655. }
  656.  
  657. func hideLoadingView() {
  658.  
  659. weak var weakSelf = self
  660.  
  661. if let strongSelf = weakSelf {
  662.  
  663. strongSelf.loadingView?.stopAnimating()
  664. strongSelf.loadingView?.removeFromSuperview()
  665. strongSelf.loadingView = nil
  666. }
  667. }
  668.  
  669.  
  670. // MARK: - Gestures
  671.  
  672. private func enablePopGesture(enable: Bool) {
  673.  
  674. if let navigationController = self.navigationController {
  675.  
  676. navigationController.interactivePopGestureRecognizer?.enabled = (enable && navigationController.viewControllers.count > 1)
  677. }
  678. }
  679.  
  680.  
  681. // MARK: - Send Analytics
  682.  
  683. func sendAnalyticsEvent(category: String, action: String, label: String, value:NSNumber?) {
  684.  
  685. let tracker = GAI.sharedInstance().defaultTracker
  686. let event = GAIDictionaryBuilder.createEventWithCategory(category, action:action, label: label, value: value)
  687. if let builtEvent = event.build() as [NSObject : AnyObject]! {
  688.  
  689. tracker.send(builtEvent)
  690. }
  691. }
  692. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement