ActionSheetPopoverPresenter.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. //
  2. // ActionSheetPopoverPresenter.swift
  3. // Sheeeeeeeeet
  4. //
  5. // Created by Daniel Saidi on 2017-11-24.
  6. // Copyright © 2017 Daniel Saidi. All rights reserved.
  7. //
  8. /*
  9. This presenter presents action sheets in a popover, just as
  10. regular UIAlertControllers are displayed on an iPad.
  11. Since popovers have an arrow that should use the same color
  12. as the rest of the popover view, this presenter will remove
  13. any header view and combine items and buttons into a single
  14. item section.
  15. */
  16. import UIKit
  17. open class ActionSheetPopoverPresenter: NSObject, ActionSheetPresenter {
  18. // MARK: - Properties
  19. open var events = ActionSheetPresenterEvents()
  20. open var isDismissableWithTapOnBackground = true
  21. var actionSheet: ActionSheet?
  22. weak var popover: UIPopoverPresentationController?
  23. // MARK: - ActionSheetPresenter
  24. public func dismiss(completion: @escaping () -> ()) {
  25. let dismissAction = { completion(); self.actionSheet = nil }
  26. let vc = actionSheet?.presentingViewController
  27. vc?.dismiss(animated: true) { dismissAction() } ?? dismissAction()
  28. }
  29. open func present(sheet: ActionSheet, in vc: UIViewController, from view: UIView?, completion: @escaping () -> ()) {
  30. setupSheetForPresentation(sheet)
  31. popover = self.popover(for: sheet, in: vc)
  32. popover?.sourceView = view
  33. popover?.sourceRect = view?.bounds ?? CGRect()
  34. vc.present(sheet, animated: true, completion: completion)
  35. }
  36. open func present(sheet: ActionSheet, in vc: UIViewController, from item: UIBarButtonItem, completion: @escaping () -> ()) {
  37. setupSheetForPresentation(sheet)
  38. popover = self.popover(for: sheet, in: vc)
  39. popover?.barButtonItem = item
  40. vc.present(sheet, animated: true, completion: completion)
  41. }
  42. open func refreshActionSheet() {
  43. guard let sheet = actionSheet else { return }
  44. sheet.headerViewContainer?.isHidden = true
  45. sheet.buttonsTableView?.isHidden = true
  46. sheet.preferredContentSize.height = sheet.itemsHeight
  47. popover?.backgroundColor = sheet.itemsTableView?.backgroundColor
  48. }
  49. }
  50. // MARK: - UIPopoverPresentationControllerDelegate
  51. extension ActionSheetPopoverPresenter: UIPopoverPresentationControllerDelegate {
  52. public func popoverPresentationControllerShouldDismissPopover(_ controller: UIPopoverPresentationController) -> Bool {
  53. guard isDismissableWithTapOnBackground else { return false }
  54. events.didDismissWithBackgroundTap?()
  55. dismiss {}
  56. return false
  57. }
  58. }
  59. // MARK: - Internal Functions
  60. extension ActionSheetPopoverPresenter {
  61. func popover(for sheet: ActionSheet, in vc: UIViewController) -> UIPopoverPresentationController? {
  62. let popover = sheet.popoverPresentationController
  63. popover?.delegate = self
  64. return popover
  65. }
  66. func setupSheetForPresentation(_ sheet: ActionSheet) {
  67. self.actionSheet = sheet
  68. sheet.items = popoverItems(for: sheet)
  69. sheet.buttons = []
  70. sheet.modalPresentationStyle = .popover
  71. }
  72. }
  73. // MARK: - Private Functions
  74. private extension ActionSheetPopoverPresenter {
  75. func popoverItems(for sheet: ActionSheet) -> [ActionSheetItem] {
  76. let items: [ActionSheetItem] = sheet.items + sheet.buttons
  77. return items.filter { !($0 is ActionSheetCancelButton) }
  78. }
  79. }