diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b765ec..4aa8e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ # CHANGELOG -The changelog for `Pai`. Also see the [releases](https://github.com/lkmfz/Pai/releases) on GitHub. +The changelog for `Pai`. Also see the [releases](https://github.com/kaodim/Pai/releases) on GitHub. -------------------------------------- ## Upcoming Releases -### [Pre-release 0.1.0](https://github.com/lkmfz/Ubud/releases/tag/0.1.0) \ No newline at end of file +### [Pre-release 0.1.0](https://github.com/kaodim/Pai/releases/tag/0.1.0) + +### [Pre-release 0.2.0](https://github.com/kaodim/Pai/releases/tag/0.2.0) +* Alignment user interface & specs according to [Kaodim](https://github.com/kaodim) product needs. +* Ownership transfer of the project to [Kaodim](https://github.com/kaodim). \ No newline at end of file diff --git a/Pai-Example/Pai-Example.xcodeproj/project.pbxproj b/Pai-Example/Pai-Example.xcodeproj/project.pbxproj index 589342d..ed14967 100644 --- a/Pai-Example/Pai-Example.xcodeproj/project.pbxproj +++ b/Pai-Example/Pai-Example.xcodeproj/project.pbxproj @@ -246,7 +246,7 @@ attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0920; - ORGANIZATIONNAME = "Luqman Fauzi"; + ORGANIZATIONNAME = Kaodim; TargetAttributes = { D588F2831FEBF54000AEE201 = { CreatedOnToolsVersion = 9.2; @@ -638,7 +638,7 @@ DEVELOPMENT_TEAM = R2XF3NYPAG; INFOPLIST_FILE = "Pai-Example/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "me.luqmanfauzi.Pai-Example"; + PRODUCT_BUNDLE_IDENTIFIER = "com.kaodim.pai-example"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -654,7 +654,7 @@ DEVELOPMENT_TEAM = R2XF3NYPAG; INFOPLIST_FILE = "Pai-Example/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "me.luqmanfauzi.Pai-Example"; + PRODUCT_BUNDLE_IDENTIFIER = "com.kaodim.pai-example"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Pai-Example/Pai-Example/ExampleViewController.swift b/Pai-Example/Pai-Example/ExampleViewController.swift index 52f6b69..56d3da9 100644 --- a/Pai-Example/Pai-Example/ExampleViewController.swift +++ b/Pai-Example/Pai-Example/ExampleViewController.swift @@ -67,10 +67,11 @@ final class ExampleViewController: UIViewController, PaiCalendarDelegate, PaiCal title = month + " " + year } - // MARK: - PaiCalendarDataSourc - - func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiDateEvent] { - let events = PaiDateEvent.generateRandom(numberOfEvents: 6) + // MARK: - PaiCalendarDataSource3 + func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiMonthEvent] { + let events = PaiMonthEvent.generateRandom(numberOfEvents: 6, numberOfDays: 3, monthYearArr: ["2018 3","2018 4","2018 5"]) return events + + } } diff --git a/Pai-Example/Podfile.lock b/Pai-Example/Podfile.lock index 398d778..f6d06c8 100644 --- a/Pai-Example/Podfile.lock +++ b/Pai-Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - Pai (0.0.1) + - Pai (0.1.0) DEPENDENCIES: - Pai (from `../`) @@ -9,8 +9,8 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - Pai: 99dbbbd7bb121d409120d3de14b10544a1a4bea9 + Pai: 5bc90c0dd19da9faf2bae514e2b75909b9fdde26 PODFILE CHECKSUM: b2f25666c2d0afccc931dbd6c838c61a7bf216f7 -COCOAPODS: 1.3.1 +COCOAPODS: 1.4.0 diff --git a/Pai.podspec b/Pai.podspec index 08505ad..ec649e7 100644 --- a/Pai.podspec +++ b/Pai.podspec @@ -1,14 +1,13 @@ Pod::Spec.new do |s| s.name = 'Pai' - s.version = '0.1.0' + s.version = '0.2.0' s.license = { :type => "MIT", :file => "LICENSE.md" } s.summary = 'Calendar view library for iOS.' - s.homepage = 'https://github.com/lkmfz/Pai' - s.social_media_url = 'https://twitter.com/lkmfz' - s.author = { "Luqman Fauzi" => "luckman.fauzi@gmail.com" } + s.homepage = 'https://github.com/kaodim/Pai' + s.author = { "Kaodim" => "tech@kaodim.com" } - s.source = { :git => 'https://github.com/lkmfz/Pai.git', :tag => s.version } + s.source = { :git => 'https://github.com/kaodim/Pai.git', :tag => s.version } s.source_files = 'Pai/Sources/**/*.swift' s.pod_target_xcconfig = { diff --git a/Pai.xcodeproj/project.pbxproj b/Pai.xcodeproj/project.pbxproj index 726eeb4..1eee8f5 100644 --- a/Pai.xcodeproj/project.pbxproj +++ b/Pai.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ D588F2691FEBF48C00AEE201 /* Pai.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D588F25F1FEBF48C00AEE201 /* Pai.framework */; }; D588F26E1FEBF48C00AEE201 /* PaiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D588F26D1FEBF48C00AEE201 /* PaiTests.swift */; }; D588F2701FEBF48C00AEE201 /* Pai.h in Headers */ = {isa = PBXBuildFile; fileRef = D588F2621FEBF48C00AEE201 /* Pai.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D59A40C0207C5E1D00F6B3A2 /* PaiMonthEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59A40BF207C5E1C00F6B3A2 /* PaiMonthEvent.swift */; }; D5A0EB682007DA9E00CC4A2E /* PaiDateEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0EB672007DA9E00CC4A2E /* PaiDateEvent.swift */; }; D5D3AD8B2006F113002C74E4 /* UICollectionView+Custom.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D3AD8A2006F113002C74E4 /* UICollectionView+Custom.swift */; }; D5D3AD9220071787002C74E4 /* PaiCalendarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D3AD9120071787002C74E4 /* PaiCalendarDelegate.swift */; }; @@ -46,6 +47,7 @@ D588F2681FEBF48C00AEE201 /* PaiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PaiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D588F26D1FEBF48C00AEE201 /* PaiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaiTests.swift; sourceTree = ""; }; D588F26F1FEBF48C00AEE201 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D59A40BF207C5E1C00F6B3A2 /* PaiMonthEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaiMonthEvent.swift; path = Pai/Sources/Models/PaiMonthEvent.swift; sourceTree = SOURCE_ROOT; }; D5A0EB672007DA9E00CC4A2E /* PaiDateEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaiDateEvent.swift; sourceTree = ""; }; D5D3AD8A2006F113002C74E4 /* UICollectionView+Custom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Custom.swift"; sourceTree = ""; }; D5D3AD9120071787002C74E4 /* PaiCalendarDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaiCalendarDelegate.swift; sourceTree = ""; }; @@ -107,6 +109,7 @@ D5D3AD93200756B1002C74E4 /* PaiMonth.swift */, D5D3AD95200756F8002C74E4 /* PaiDate.swift */, D5A0EB672007DA9E00CC4A2E /* PaiDateEvent.swift */, + D59A40BF207C5E1C00F6B3A2 /* PaiMonthEvent.swift */, ); path = Models; sourceTree = ""; @@ -243,7 +246,7 @@ attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0920; - ORGANIZATIONNAME = "Luqman Fauzi"; + ORGANIZATIONNAME = Kaodim; TargetAttributes = { D588F25E1FEBF48C00AEE201 = { CreatedOnToolsVersion = 9.2; @@ -323,6 +326,7 @@ D5E3FCE51FF28CF90059433E /* MonthHeaderView.swift in Sources */, D54FC8EF1FECA8FD00EC148D /* MonthCollectionView.swift in Sources */, D5D3AD9220071787002C74E4 /* PaiCalendarDelegate.swift in Sources */, + D59A40C0207C5E1D00F6B3A2 /* PaiMonthEvent.swift in Sources */, D5D3AD8B2006F113002C74E4 /* UICollectionView+Custom.swift in Sources */, D5E3FCF11FF2BBFA0059433E /* DayCollectionView.swift in Sources */, D54FC8F61FECB04E00EC148D /* DayViewCell.swift in Sources */, @@ -475,7 +479,7 @@ INFOPLIST_FILE = "Pai/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = me.luqmanfauzi.Pai; + PRODUCT_BUNDLE_IDENTIFIER = com.kaodim.pai; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -498,7 +502,7 @@ INFOPLIST_FILE = "Pai/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = me.luqmanfauzi.Pai; + PRODUCT_BUNDLE_IDENTIFIER = com.kaodim.pai; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_VERSION = 4.0; diff --git a/Pai/Sources/Models/PaiDateEvent.swift b/Pai/Sources/Models/PaiDateEvent.swift index 4a57bab..c52fceb 100644 --- a/Pai/Sources/Models/PaiDateEvent.swift +++ b/Pai/Sources/Models/PaiDateEvent.swift @@ -12,29 +12,28 @@ public struct PaiDateEvent { public let date: Date - public let name: String? + public let tagColors: [UIColor] - public let tagColor: UIColor + public var monthYearStr: String { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy M" + return formatter.string(from: date) + } + + public var dateStr: String { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy M dd" + return formatter.string(from: date) + + } /// Initlizer of the struct /// /// - Parameters: /// - date: `Date` of event - /// - name: optional `String` of event name - /// - tagColor: `UIColor` tag color of event - public static func initObject(date: Date, name: String?, tagColor: UIColor) -> PaiDateEvent { - return PaiDateEvent(date: date, name: name, tagColor: tagColor) + /// - tagColors: `[UIColor]` array of tag color + public static func initObject(date: Date, tagColors: [UIColor]) -> PaiDateEvent { + return PaiDateEvent(date: date, tagColors: tagColors) } } -public extension PaiDateEvent { - public static func generateRandom(numberOfEvents: Int) -> [PaiDateEvent] { - var events: [PaiDateEvent] = [] - for i in 1...numberOfEvents { - let color: UIColor = (i % 2 == 0) ? .red : .blue - let event = PaiDateEvent(date: Date(), name: nil, tagColor: color) - events.append(event) - } - return events - } -} diff --git a/Pai/Sources/Models/PaiMonthEvent.swift b/Pai/Sources/Models/PaiMonthEvent.swift new file mode 100644 index 0000000..7af44c2 --- /dev/null +++ b/Pai/Sources/Models/PaiMonthEvent.swift @@ -0,0 +1,61 @@ +// +// PaiMonthEvent.swift +// Pai +// +// Created by augustius cokroe on 23/03/2018. +// + +import Foundation + +public struct PaiMonthEvent { + + public let monthYearStr: String // yyyy M + + public let monthEvents: [PaiDateEvent] + + /// Initlizer of the struct + /// + /// - Parameters: + /// - monthYearStr: date of event in `yyyy M` format + /// - monthEvents: array of PaiDateEvent object + public static func initObject(monthYearStr: String, monthEvents: [PaiDateEvent]) -> PaiMonthEvent { + return PaiMonthEvent(monthYearStr: monthYearStr, monthEvents: monthEvents) + } +} + +public extension PaiMonthEvent { + /// Generate random events + /// + /// - Parameters: + /// - numberOfEvents: `Date` of event + /// - numberOfDays: `[UIColor]` array of tag color + /// - monthYearArr: `[String]` array of string of date with format `yyyy M` + public static func generateRandom(numberOfEvents: Int, numberOfDays: Int, monthYearArr: [String]) -> [PaiMonthEvent] { + + /// get array of color for each day + var tagColors = [UIColor]() + for i in 1...numberOfEvents { + let color: UIColor = (i % 2 == 0) ? .red : .blue + tagColors.append(color) + } + + /// get array of PaiMonthEvent with events + var monthEvents: [PaiMonthEvent] = [] + let secondsInDays: TimeInterval = 60 * 60 * 24 + for (index,str) in monthYearArr.enumerated() { + var dayEvents: [PaiDateEvent] = [] + for day in 1...numberOfDays { + var date = Date().addingTimeInterval(Double(day - 1) * secondsInDays) + date = Calendar.current.date(byAdding: .month, value: index, to: date) ?? Date() + let event = PaiDateEvent(date: date, tagColors: tagColors) + dayEvents.append(event) + } + let mEvent = PaiMonthEvent.initObject(monthYearStr: str, monthEvents: dayEvents) + monthEvents.append(mEvent) + } + + return monthEvents + } +} + + diff --git a/Pai/Sources/Protocols/PaiCalendarDelegate.swift b/Pai/Sources/Protocols/PaiCalendarDelegate.swift index 196f770..b73f223 100644 --- a/Pai/Sources/Protocols/PaiCalendarDelegate.swift +++ b/Pai/Sources/Protocols/PaiCalendarDelegate.swift @@ -10,15 +10,15 @@ import Foundation public protocol PaiCalendarDataSource: class { - /// List of `[PaiDateEvent]` events to be displayed in calendar + /// List of `[PaiMonthEvent]` events to be displayed in calendar /// /// - Parameter calendar: `MonthCollectionView` /// - Returns: list of all events to be displayed in the calendar view - func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiDateEvent] + func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiMonthEvent] } public extension PaiCalendarDataSource { - func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiDateEvent] { + func calendarDateEvents(in calendar: MonthCollectionView) -> [PaiMonthEvent] { return [] } } @@ -41,9 +41,18 @@ public protocol PaiCalendarDelegate: class { /// - month: string of selected month /// - year: string of selected year func calendarMonthViewDidScroll(in calendar: MonthCollectionView, at index: Int, month: String, year: String) + + /// Send month string when month cell is currently at top of screen + /// + /// - Parameters: + /// - calendar: `MonthCollectionView` + /// - datesString: array of formattable date string of current visible month [yyyy-MM-dd] + func calendarMonthVisibleMonth(in calendar: MonthCollectionView, datesString: [String]) } public extension PaiCalendarDelegate { func calendarDateDidSelect(in calendar: MonthCollectionView, at index: Int, date: PaiDate) { } func calendarMonthViewDidScroll(in calendar: MonthCollectionView, at index: Int, month: String, year: String) { } + func calendarMonthVisibleMonth(in calendar: MonthCollectionView, datesString: [String]) { } } + diff --git a/Pai/Sources/Views/DayCollectionView.swift b/Pai/Sources/Views/DayCollectionView.swift index 10ac780..4bbe039 100644 --- a/Pai/Sources/Views/DayCollectionView.swift +++ b/Pai/Sources/Views/DayCollectionView.swift @@ -8,7 +8,7 @@ import Foundation -internal typealias DailyEventsItem = (date: Date, events: [PaiDateEvent]) +internal typealias DailyEventsItem = (date: Date, event: PaiDateEvent?) public class DayCollectionView: UICollectionView { @@ -54,18 +54,28 @@ public class DayCollectionView: UICollectionView { /// - Parameters: /// - month: `PaiMonth` /// - events: events in particular `PaiMonth` - public func configure(_ month: PaiMonth, _ events: [PaiDateEvent]) { + public func configure(_ month: PaiMonth, _ events: PaiMonthEvent?) { self.month = month - /// Map events of the particular date, according to collectionView item index. - var items: [DailyEventsItem] = [] - dates.map({ $0.date }).forEach { (date) in - let dailyEvents = events.filter({ - Calendar.autoupdatingCurrent.compare($0.date, to: date, toGranularity: .day) == .orderedSame - }) - let item: DailyEventsItem = (date, dailyEvents) - items.append(item) + /// initiate dailyEventsItems + dailyEventsItems = dates.map({ + let items: DailyEventsItem = ($0.date, nil) + return items + }) + + guard let events = events else { return } + + let allDateStr = Set(events.monthEvents.map({$0.dateStr}).sorted()) + allDateStr.forEach { (dateStr) in + let dayEvent = events.monthEvents.first(where: {$0.dateStr == dateStr}) + if let index = dailyEventsItems.index(where: { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy M dd" + return formatter.string(from: $0.date) == dateStr + }) { + dailyEventsItems[index] = (dates[index].date, dayEvent) + } } - dailyEventsItems = items + reloadData() } } @@ -81,8 +91,8 @@ extension DayCollectionView: UICollectionViewDataSource, UICollectionViewDelegat guard let cell = collectionView.dequeueReusableCell(withClass: DayViewCell.self, for: indexPath), let monthItem = month - else { - fatalError("DayViewCell not found.") + else { + fatalError("DayViewCell not found.") } let dateItem = dates[indexPath.item] @@ -127,3 +137,4 @@ extension DayCollectionView: UICollectionViewDataSource, UICollectionViewDelegat return CGSize(width: itemWidth, height: itemHeight) } } + diff --git a/Pai/Sources/Views/DayViewCell.swift b/Pai/Sources/Views/DayViewCell.swift index d695cf4..8228d0b 100644 --- a/Pai/Sources/Views/DayViewCell.swift +++ b/Pai/Sources/Views/DayViewCell.swift @@ -47,25 +47,8 @@ final class DayViewCell: UICollectionViewCell { return view }() - private lazy var eventViews: [UIView] = { - let maxStacks = 6 - var views: [UIView] = [] - for i in 1...maxStacks { - let view: UIView - if i == maxStacks { - view = dotsIndicator - } else { - view = UIView() - } - view.translatesAutoresizingMaskIntoConstraints = false - view.heightAnchor.constraint(equalToConstant: 3.0).isActive = true - views.append(view) - } - return views - }() - private lazy var eventsStackView: UIStackView = { - let view = UIStackView(arrangedSubviews: self.eventViews) + let view = UIStackView() view.translatesAutoresizingMaskIntoConstraints = false view.axis = .vertical view.isBaselineRelativeArrangement = true @@ -99,7 +82,7 @@ final class DayViewCell: UICollectionViewCell { eventsStackView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor), eventsStackView.centerXAnchor.constraint(equalTo: centerXAnchor), eventsStackView.widthAnchor.constraint(equalToConstant: bounds.width - 15.0) - ]) + ]) } } @@ -110,24 +93,38 @@ final class DayViewCell: UICollectionViewCell { } public func configureEvent(item: DailyEventsItem) { - guard PaiStyle.shared.dateItemDisplayEventsIfAny, !(item.events.isEmpty) else { + guard PaiStyle.shared.dateItemDisplayEventsIfAny, let event = item.event else { eventsStackView.isHidden = true return } eventsStackView.isHidden = false - if item.events.count <= 5 { - /// Remove last subview in stackview. - eventsStackView.removeArrangedSubview(eventsStackView.arrangedSubviews.last!) - eventViews.last?.removeFromSuperview() - } - for (index, event) in item.events.enumerated() { - if 0...4 ~= index { - /// Within 5 events range - eventsStackView.arrangedSubviews[index].backgroundColor = event.tagColor + dotsIndicator.removeFromSuperview() + let eventView = getEventView(event: event) + eventsStackView.arrangedSubviews.forEach({eventsStackView.removeArrangedSubview($0)}) + eventView.forEach({eventsStackView.addArrangedSubview($0)}) + } + + private func getEventView(event: PaiDateEvent) -> [UIView] { + let maxStacks = 6 + let stacks = event.tagColors.count + var views: [UIView] = [] + for (index,color) in event.tagColors.enumerated() { + let view: UIView + if (index + 1) == maxStacks { + view = dotsIndicator + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: 3.0).isActive = true + views.append(view) + return views } else { - break + view = UIView() + view.backgroundColor = color + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: 3.0).isActive = true + views.append(view) } } + return views } public func configure(style: DateItemStyle) { @@ -158,3 +155,4 @@ final class DayViewCell: UICollectionViewCell { } } } + diff --git a/Pai/Sources/Views/MonthCollectionView.swift b/Pai/Sources/Views/MonthCollectionView.swift index 4a33435..01e7081 100644 --- a/Pai/Sources/Views/MonthCollectionView.swift +++ b/Pai/Sources/Views/MonthCollectionView.swift @@ -8,7 +8,7 @@ import UIKit -internal typealias MonthlyEventsItem = (month: PaiMonth, events: [PaiDateEvent]) +internal typealias MonthlyEventsItem = (month: PaiMonth, events: PaiMonthEvent?) public class MonthCollectionView: UICollectionView { @@ -16,15 +16,12 @@ public class MonthCollectionView: UICollectionView { public var sharedStyle: PaiStyle public weak var calendarDelegate: PaiCalendarDelegate? + public weak var calendarDataSource: PaiCalendarDataSource? // MARK: - Private Properties private var months: [PaiMonth]! - private var montlyEventsItems: [MonthlyEventsItem] = [] { - didSet { - reloadData() - } - } + private var montlyEventsItems: [MonthlyEventsItem] = [] private var mostTopMonth: PaiMonth? private var currentlyScrollToCurrentMonth = false private var currentMonthIndex: IndexPath!{ @@ -58,8 +55,14 @@ public class MonthCollectionView: UICollectionView { showsVerticalScrollIndicator = false NotificationCenter.default.addObserver(self, selector: #selector(dateDidSelect), name: NSNotification.Name(rawValue: "me.luqmanfauzi.Pai"), object: nil) + /// Initialiaze date events + montlyEventsItems = self.months.map({ + let monthlyEvent: MonthlyEventsItem = ($0, nil) + return monthlyEvent + }) /// Setup date events if let events = calendarDataSource?.calendarDateEvents(in: self) { + self.calendarDataSource = calendarDataSource mapEventsForParticularMonths(events: events) } @@ -78,6 +81,12 @@ public class MonthCollectionView: UICollectionView { NotificationCenter.default.removeObserver(self) } + public func reloadEvents() { + if let events = calendarDataSource?.calendarDateEvents(in: self) { + mapEventsForParticularMonths(events: events) + } + } + // MARK: - Private Methods /// Notification center event from tapping day item cell. @@ -92,34 +101,31 @@ public class MonthCollectionView: UICollectionView { calendarDelegate?.calendarDateDidSelect(in: self, at: index, date: date) } + /// Send visible months to outside library + private func sendVisibleCell() { + /// Send back array of current visible month after scrolling + var visibleMonthsStr = [String]() + for cell in visibleCells { + if let indexPath = indexPath(for: cell) { + let selectedMonth = months[indexPath.section] + let selectedMonthStr = "\(selectedMonth.year)-\(selectedMonth.month.rawValue + 1)-15" + visibleMonthsStr.append(selectedMonthStr) + } + } + print(visibleMonthsStr) + calendarDelegate?.calendarMonthVisibleMonth(in: self, datesString: visibleMonthsStr) + } + /// Map all events into particular months /// - /// - Parameter events: All `[PaiDateEvent]` events from outside library. - private func mapEventsForParticularMonths(events: [PaiDateEvent]) { - var items: [MonthlyEventsItem] = [] - months.forEach { (monthItem) in - let currentMonthNumber: String = (monthItem.month.rawValue + 1).description - let currentYear: String = monthItem.year.description - - /// Get all events in this particular month & year. - let events = events.filter({ event in - /// Filter event of the year. - let formatter = DateFormatter() - formatter.dateFormat = "yyyy" - let yearString: String = formatter.string(from: event.date) - return (currentYear == yearString) - }).filter({ event in - /// Filter event of the month. - let formatter = DateFormatter() - formatter.dateFormat = "M" - let monthNumber: String = formatter.string(from: event.date) - return (currentMonthNumber == monthNumber) - }) - - let monthlyEvent: MonthlyEventsItem = (monthItem, events) - items.append(monthlyEvent) + /// - Parameter events: All `[PaiMonthEvent]` events from outside library. + private func mapEventsForParticularMonths(events: [PaiMonthEvent]) { + events.forEach { (monthEvents) in + if let index = montlyEventsItems.index(where: {"\($0.month.year) \($0.month.month.rawValue + 1)" == monthEvents.monthYearStr}) { + montlyEventsItems[index] = (months[index] , monthEvents) + } } - montlyEventsItems = items + reloadData() } /// Scroll to current month, which contains today. @@ -129,14 +135,11 @@ public class MonthCollectionView: UICollectionView { let components = Calendar.autoupdatingCurrent.dateComponents([.year, .month, .day], from: Date()) let currentMonth = components.month let currentYear = components.year - guard let indexTarget = months.enumerated() - .filter({ $0.element.year == currentYear }) - .filter({ $0.element.month.rawValue + 1 == currentMonth }) - .first?.offset - else { - return - } - let indexPath = IndexPath(item: 0, section: indexTarget) + guard + let index = months.index(where: { $0.year == currentYear && $0.month.rawValue + 1 == currentMonth }) + else { return } + + let indexPath = IndexPath(item: 0, section: index) scrollToItem(at: indexPath, at: .top, animated: true) currentMonthIndex = indexPath } @@ -168,10 +171,10 @@ extension MonthCollectionView: UICollectionViewDataSource, UICollectionViewDeleg public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { guard let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, - withClass: MonthHeaderView.self, - for: indexPath) - else { - fatalError("MonthlyHeaderReusableView not found.") + withClass: MonthHeaderView.self, + for: indexPath) + else { + fatalError("MonthlyHeaderReusableView not found.") } let month = months[indexPath.section] headerView.configure(monthSymbol: month.symbol, year: month.year) @@ -209,6 +212,16 @@ extension MonthCollectionView: UICollectionViewDataSource, UICollectionViewDeleg } } + public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { + if !decelerate { + sendVisibleCell() + } + } + + public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + sendVisibleCell() + } + public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { if currentlyScrollToCurrentMonth { currentlyScrollToCurrentMonth = false @@ -221,3 +234,4 @@ extension MonthCollectionView: UICollectionViewDataSource, UICollectionViewDeleg } } } + diff --git a/Pai/Supporting Files/Info.plist b/Pai/Supporting Files/Info.plist index d725449..23d96cb 100644 --- a/Pai/Supporting Files/Info.plist +++ b/Pai/Supporting Files/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.1.0 + 0.2.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass