/Malendar/CVCalendar/CVCalendarView.swift

https://github.com/croossin/Malendar · Swift · 325 lines · 249 code · 58 blank · 18 comment · 43 complexity · 46811839ae4c7041a6ca21df6136c23c MD5 · raw file

  1. //
  2. // CVCalendarView.swift
  3. // CVCalendar
  4. //
  5. // Created by E. Mozharovsky on 12/26/14.
  6. // Copyright (c) 2014 GameApp. All rights reserved.
  7. //
  8. import UIKit
  9. public typealias WeekView = CVCalendarWeekView
  10. public typealias CalendarView = CVCalendarView
  11. public typealias MonthView = CVCalendarMonthView
  12. public typealias Manager = CVCalendarManager
  13. public typealias DayView = CVCalendarDayView
  14. public typealias ContentController = CVCalendarContentViewController
  15. public typealias Appearance = CVCalendarViewAppearance
  16. public typealias Coordinator = CVCalendarDayViewControlCoordinator
  17. public typealias Date = CVDate
  18. public typealias CalendarMode = CVCalendarViewPresentationMode
  19. public typealias Weekday = CVCalendarWeekday
  20. public typealias Animator = CVCalendarViewAnimator
  21. public typealias Delegate = CVCalendarViewDelegate
  22. public typealias AppearanceDelegate = CVCalendarViewAppearanceDelegate
  23. public typealias AnimatorDelegate = CVCalendarViewAnimatorDelegate
  24. public typealias ContentViewController = CVCalendarContentViewController
  25. public typealias MonthContentViewController = CVCalendarMonthContentViewController
  26. public typealias WeekContentViewController = CVCalendarWeekContentViewController
  27. public typealias MenuViewDelegate = CVCalendarMenuViewDelegate
  28. public typealias TouchController = CVCalendarTouchController
  29. public typealias SelectionType = CVSelectionType
  30. public final class CVCalendarView: UIView {
  31. // MARK: - Public properties
  32. public var manager: Manager!
  33. public var appearance: Appearance!
  34. public var touchController: TouchController!
  35. public var coordinator: Coordinator!
  36. public var animator: Animator!
  37. public var contentController: ContentViewController!
  38. public var calendarMode: CalendarMode!
  39. public var (weekViewSize, dayViewSize): (CGSize?, CGSize?)
  40. private var validated = false
  41. public var firstWeekday: Weekday {
  42. get {
  43. if let delegate = delegate {
  44. return delegate.firstWeekday()
  45. } else {
  46. return .Sunday
  47. }
  48. }
  49. }
  50. public var shouldShowWeekdaysOut: Bool! {
  51. if let delegate = delegate, let shouldShow = delegate.shouldShowWeekdaysOut?() {
  52. return shouldShow
  53. } else {
  54. return false
  55. }
  56. }
  57. public var presentedDate: Date! {
  58. didSet {
  59. if let oldValue = oldValue {
  60. delegate?.presentedDateUpdated?(presentedDate)
  61. }
  62. }
  63. }
  64. public var shouldAnimateResizing: Bool {
  65. get {
  66. if let delegate = delegate, should = delegate.shouldAnimateResizing?() {
  67. return should
  68. }
  69. return true
  70. }
  71. }
  72. public var shouldAutoSelectDayOnMonthChange: Bool{
  73. get {
  74. if let delegate = delegate, should = delegate.shouldAutoSelectDayOnMonthChange?() {
  75. return should
  76. }
  77. return true
  78. }
  79. }
  80. public var shouldAutoSelectDayOnWeekChange: Bool{
  81. get {
  82. if let delegate = delegate, should = delegate.shouldAutoSelectDayOnWeekChange?() {
  83. return should
  84. }
  85. return true
  86. }
  87. }
  88. // MARK: - Calendar View Delegate
  89. @IBOutlet public weak var calendarDelegate: AnyObject? {
  90. set {
  91. if let calendarDelegate = newValue as? Delegate {
  92. delegate = calendarDelegate
  93. }
  94. }
  95. get {
  96. return delegate
  97. }
  98. }
  99. public var delegate: CVCalendarViewDelegate? {
  100. didSet {
  101. if manager == nil {
  102. manager = Manager(calendarView: self)
  103. }
  104. if appearance == nil {
  105. appearance = Appearance()
  106. }
  107. if touchController == nil {
  108. touchController = TouchController(calendarView: self)
  109. }
  110. if coordinator == nil {
  111. coordinator = Coordinator(calendarView: self)
  112. }
  113. if animator == nil {
  114. animator = Animator(calendarView: self)
  115. }
  116. if calendarMode == nil {
  117. loadCalendarMode()
  118. }
  119. }
  120. }
  121. // MARK: - Calendar Appearance Delegate
  122. @IBOutlet public weak var calendarAppearanceDelegate: AnyObject? {
  123. set {
  124. if let calendarAppearanceDelegate = newValue as? AppearanceDelegate {
  125. if appearance == nil {
  126. appearance = Appearance()
  127. }
  128. appearance.delegate = calendarAppearanceDelegate
  129. }
  130. }
  131. get {
  132. return appearance
  133. }
  134. }
  135. // MARK: - Calendar Animator Delegate
  136. @IBOutlet public weak var animatorDelegate: AnyObject? {
  137. set {
  138. if let animatorDelegate = newValue as? AnimatorDelegate {
  139. animator.delegate = animatorDelegate
  140. }
  141. }
  142. get {
  143. return animator
  144. }
  145. }
  146. // MARK: - Initialization
  147. public init() {
  148. super.init(frame: CGRectZero)
  149. hidden = true
  150. }
  151. public override init(frame: CGRect) {
  152. super.init(frame: frame)
  153. hidden = true
  154. }
  155. /// IB Initialization
  156. public required init?(coder aDecoder: NSCoder) {
  157. super.init(coder: aDecoder)
  158. hidden = true
  159. }
  160. }
  161. // MARK: - Frames update
  162. extension CVCalendarView {
  163. public func commitCalendarViewUpdate() {
  164. if let delegate = delegate, let contentController = contentController {
  165. let contentViewSize = contentController.bounds.size
  166. let selfSize = bounds.size
  167. let screenSize = UIScreen.mainScreen().bounds.size
  168. let allowed = selfSize.width <= screenSize.width && selfSize.height <= screenSize.height
  169. if !validated && allowed {
  170. let width = selfSize.width
  171. let height: CGFloat
  172. let countOfWeeks = CGFloat(6)
  173. let vSpace = appearance.spaceBetweenWeekViews!
  174. let hSpace = appearance.spaceBetweenDayViews!
  175. if let mode = calendarMode {
  176. switch mode {
  177. case .WeekView:
  178. height = selfSize.height
  179. case .MonthView :
  180. height = (selfSize.height / countOfWeeks) - (vSpace * countOfWeeks)
  181. }
  182. // If no height constraint found we set it manually.
  183. var found = false
  184. for constraint in constraints {
  185. if constraint.firstAttribute == .Height {
  186. found = true
  187. }
  188. }
  189. if !found {
  190. addConstraint(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1, constant: frame.height))
  191. }
  192. weekViewSize = CGSizeMake(width, height)
  193. dayViewSize = CGSizeMake((width / 7.0) - hSpace, height)
  194. validated = true
  195. contentController.updateFrames(selfSize != contentViewSize ? bounds : CGRectZero)
  196. }
  197. }
  198. }
  199. }
  200. }
  201. // MARK: - Coordinator callback
  202. extension CVCalendarView {
  203. public func didSelectDayView(dayView: CVCalendarDayView) {
  204. if let controller = contentController {
  205. presentedDate = dayView.date
  206. delegate?.didSelectDayView?(dayView)
  207. controller.performedDayViewSelection(dayView) // TODO: Update to range selection
  208. }
  209. }
  210. }
  211. // MARK: - Convenience API
  212. extension CVCalendarView {
  213. public func changeDaysOutShowingState(shouldShow: Bool) {
  214. contentController.updateDayViews(shouldShow)
  215. }
  216. public func toggleViewWithDate(date: NSDate) {
  217. contentController.togglePresentedDate(date)
  218. }
  219. public func toggleCurrentDayView() {
  220. contentController.togglePresentedDate(NSDate())
  221. }
  222. public func loadNextView() {
  223. contentController.presentNextView(nil)
  224. }
  225. public func loadPreviousView() {
  226. contentController.presentPreviousView(nil)
  227. }
  228. public func changeMode(mode: CalendarMode) {
  229. if let selectedDate = coordinator.selectedDayView?.date.convertedDate() where calendarMode != mode {
  230. calendarMode = mode
  231. let newController: ContentController
  232. switch mode {
  233. case .WeekView:
  234. contentController.updateHeight(dayViewSize!.height, animated: true)
  235. newController = WeekContentViewController(calendarView: self, frame: bounds, presentedDate: selectedDate)
  236. case .MonthView:
  237. contentController.updateHeight(contentController.presentedMonthView.potentialSize.height, animated: true)
  238. newController = MonthContentViewController(calendarView: self, frame: bounds, presentedDate: selectedDate)
  239. }
  240. newController.updateFrames(bounds)
  241. newController.scrollView.alpha = 0
  242. addSubview(newController.scrollView)
  243. UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
  244. self.contentController.scrollView.alpha = 0
  245. newController.scrollView.alpha = 1
  246. }) { _ in
  247. self.contentController.scrollView.removeAllSubviews()
  248. self.contentController.scrollView.removeFromSuperview()
  249. self.contentController = newController
  250. }
  251. }
  252. }
  253. }
  254. // MARK: - Mode load
  255. private extension CVCalendarView {
  256. func loadCalendarMode() {
  257. if let delegate = delegate {
  258. calendarMode = delegate.presentationMode()
  259. switch delegate.presentationMode() {
  260. case .MonthView: contentController = MonthContentViewController(calendarView: self, frame: bounds)
  261. case .WeekView: contentController = WeekContentViewController(calendarView: self, frame: bounds)
  262. default: break
  263. }
  264. addSubview(contentController.scrollView)
  265. }
  266. }
  267. }