{"id":20756375,"url":"https://github.com/kvyatkovskys/kvkcalendar","last_synced_at":"2025-05-15T04:04:26.935Z","repository":{"id":38375365,"uuid":"163867164","full_name":"kvyatkovskys/KVKCalendar","owner":"kvyatkovskys","description":"A most fully customization calendar for Apple platforms 📅","archived":false,"fork":false,"pushed_at":"2024-11-12T06:23:49.000Z","size":242769,"stargazers_count":681,"open_issues_count":24,"forks_count":127,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-15T04:04:18.889Z","etag":null,"topics":["calendar","calendar-view","carthage","cocoapods","customization-calendar","datepicker","ios","ios-calendar","ios-swift","kvkcalendar","swift","swift-package-manager","timeline","timeline-library"],"latest_commit_sha":null,"homepage":"https://kvyatkovskys.github.io/KVKCalendar/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kvyatkovskys.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"issuehunt":"kvyatkovskys"}},"created_at":"2019-01-02T16:55:30.000Z","updated_at":"2025-05-14T13:27:14.000Z","dependencies_parsed_at":"2024-02-04T16:13:41.100Z","dependency_job_id":"f165c07e-5fbf-4bda-a21a-dfde68b55eac","html_url":"https://github.com/kvyatkovskys/KVKCalendar","commit_stats":{"total_commits":783,"total_committers":16,"mean_commits":48.9375,"dds":"0.17113665389527455","last_synced_commit":"7b0fdd172cddce14e6c81d056d5750592c711c0d"},"previous_names":[],"tags_count":79,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvyatkovskys%2FKVKCalendar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvyatkovskys%2FKVKCalendar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvyatkovskys%2FKVKCalendar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvyatkovskys%2FKVKCalendar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kvyatkovskys","download_url":"https://codeload.github.com/kvyatkovskys/KVKCalendar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254270641,"owners_count":22042858,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calendar","calendar-view","carthage","cocoapods","customization-calendar","datepicker","ios","ios-calendar","ios-swift","kvkcalendar","swift","swift-package-manager","timeline","timeline-library"],"created_at":"2024-11-17T09:32:01.504Z","updated_at":"2025-05-15T04:04:26.910Z","avatar_url":"https://github.com/kvyatkovskys.png","language":"Swift","funding_links":["https://issuehunt.io/r/kvyatkovskys"],"categories":[],"sub_categories":[],"readme":"[![Version](https://img.shields.io/cocoapods/v/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)\n[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-orange.svg)](https://swiftpackageindex.com/kvyatkovskys/KVKCalendar)\n[![Platform](https://img.shields.io/cocoapods/p/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)\n[![License](https://img.shields.io/cocoapods/l/KVKCalendar.svg?style=flat)](https://cocoapods.org/pods/KVKCalendar)\n\n# KVKCalendar\n\n**KVKCalendar** is a most fully customization calendar. Library consists of five modules for displaying various types of calendar (*day*, *week*, *month*, *year*, *list of events*). You can choose any module or use all. It is designed based on a standard iOS calendar, but with additional features. Timeline displays the schedule for the day and the week.\n\n**Additional features:**\n- [x] Switch between time zones\n- [x] Dark mode\n- [ ] Skeleton loading (month/list)\n- [x] Custom event view\n- [x] Custom date cell\n- [x] Custom header view and collection view\n- [x] Custom calendar localization\n- [x] Event list mode for weekly viewing\n- [x] Ability to set a divider line (day/week)\n- [x] [Supporting Multiple Windows on iPad](https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/multitasking/)\n- [x] UIMenu supports in event view (iOS and Mac Catalyst 14.0+)\n- [x] [Ability to configure the frame for viewing events](https://github.com/kvyatkovskys/KVKCalendar/pull/198)\n\n\n\u003cimg src=\"Screenshots/iphone_day.png\" width=\"350\" height=\"650\"\u003e\n\n\n## Need Help?\n\nIf you have a **question** about how to use KVKCalendar in your application, ask it on StackOverflow using the [KVKCalendar](https://stackoverflow.com/questions/tagged/kvkcalendar) tag.\n\nPlease, use [Issues](https://github.com/kvyatkovskys/KVKCalendar/issues) only for reporting **bugs** or requesting a new **features** in the library.\n\n## Requirements\n\n- iOS 13.0+, iPadOS 13.0+, MacOS 11.0+ (supports Mac Catalyst)\n- Swift 5.0+\n\n## Installation\n\n**KVKCalendar** is available through [CocoaPods](https://cocoapods.org) or [Swift Package Manager](https://swift.org/package-manager/).\n\n### CocoaPods\n~~~bash\npod 'KVKCalendar'\n~~~\n\n[Adding Pods to an Xcode project](https://guides.cocoapods.org/using/using-cocoapods.html)\n\n### Swift Package Manager (Xcode 12 or higher)\n\n1. In Xcode navigate to **File** → **Swift Packages** → **Add Package Dependency...**\n2. Select a project\n3. Paste the repository URL (`https://github.com/kvyatkovskys/KVKCalendar`) and click **Next**.\n4. For **Rules**, select **Version (Up to Next Major)** and click **Next**.\n5. Click **Finish**.\n\n[Adding Package Dependencies to Your App](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app)\n\n## Usage for UIKit\n\nImport `KVKCalendar`.\nCreate a subclass view `CalendarView` and implement `CalendarDataSource` protocol. Create an array of class `[Event]` and return the array.\n\n```swift\nimport KVKCalendar\n\nclass ViewController: UIViewController {\n    var events = [Event]()\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        let calendar = CalendarView(frame: frame)\n        calendar.dataSource = self\n        view.addSubview(calendar)\n        \n        createEvents { (events) in\n            self.events = events\n            self.calendarView.reloadData()\n        }\n    }\n    \n    override func viewWillLayoutSubviews() {\n        super.viewWillLayoutSubviews()\n        // to track changing frame when an user rotates device\n        calendarView.reloadFrame(view.frame)\n    }\n}\n\nextension ViewController {\n    func createEvents(completion: ([Event]) -\u003e Void) {\n        let models = // Get events from storage / API\n        \n        let events = models.compactMap({ (item) in\n            var event = Event(ID: item.id)\n            event.start = item.startDate // start date event\n            event.end = item.endDate // end date event\n            event.color = item.color\n            event.isAllDay = item.allDay\n            event.isContainsFile = !item.files.isEmpty\n            event.recurringType = // recurring event type - .everyDay, .everyWeek\n        \n            // Add text event (title, info, location, time)\n            if item.allDay {\n                event.text = \"\\(item.title)\"\n            } else {\n                event.text = \"\\(startTime) - \\(endTime)\\n\\(item.title)\"\n            }\n            return event\n        })\n        completion(events)\n    }\n}\n\nextension ViewController: CalendarDataSource {\n    func eventsForCalendar(systemEvents: [EKEvent]) -\u003e [Event] {\n        // if you want to get events from iOS calendars\n        // set calendar names to style.systemCalendars = [\"Test\"]\n        let mappedEvents = systemEvents.compactMap { Event(event: $0) }\n        return events + mappedEvents\n    }\n}\n```\n\nImplement `CalendarDelegate` to handle user action and control calendar behaviour.\n\n```swift\ncalendar.delegate = self\n```\n\nTo use a custom view for specific event or date you need to create a new view of class `EventViewGeneral` and return the view in function.\n\n```swift\nclass CustomViewEvent: EventViewGeneral {\n    override init(style: Style, event: Event, frame: CGRect) {\n        super.init(style: style, event: event, frame: frame)\n    }\n}\n\n// an optional function from CalendarDataSource\nfunc willDisplayEventView(_ event: Event, frame: CGRect, date: Date?) -\u003e EventViewGeneral? {\n    guard event.ID == id else { return nil }\n    \n    return customEventView\n}\n```\n\n\u003cimg src=\"Screenshots/custom_event_view.png\" width=\"300\"\u003e\n\nTo use a custom date cell, just subscribe on this optional method from `CalendarDataSource` (works for Day/Week/Month/Year views).\n```swift\nfunc dequeueCell\u003cT\u003e(parameter: CellParameter, type: CalendarType, view: T, indexPath: IndexPath) -\u003e KVKCalendarCellProtocol? where T: UIScrollView { \n    switch type {\n    case .year:\n        let cell = (view as? UICollectionView)?.dequeueCell(indexPath: indexPath) { (cell: CustomYearCell) in\n            // configure the cell\n        }\n        return cell\n    case .day, .week, .month:    \n        let cell = (view as? UICollectionView)?.dequeueCell(indexPath: indexPath) { (cell: CustomDayCell) in\n            // configure the cell\n        }\n        return cell\n    case .list:    \n        let cell = (view as? UITableView)?.dequeueCell { (cell: CustomListCell) in\n            // configure the cell\n        }\n        return cell\n    }\n}\n```\n\n\u003cimg src=\"Screenshots/custom_day_cell.png\" width=\"300\"\u003e\n\n## Usage for SwiftUI\n\nAdd a new `SwiftUI` file and import `KVKCalendar`.\nCreate a struct `CalendarViewDisplayable` and declare the protocol `UIViewRepresentable` for connection `UIKit` with `SwiftUI`.\n\n```swift\nimport SwiftUI\nimport KVKCalendar\n\nstruct CalendarViewDisplayable: UIViewRepresentable {\n\n    @Binding var events: [Event]\n    var selectDate = Date()\n    var style = Style()\n    \n    private var calendar = KVKalendarView(frame: .zero)\n        \n    func makeUIView(context: UIViewRepresentableContext\u003cCalendarViewDisplayable\u003e) -\u003e KVKCalendarView {\n        calendar.dataSource = context.coordinator\n        calendar.delegate = context.coordinator\n        return calendar\n    }\n    \n    func updateUIView(_ uiView: KVKCalendarView, context: UIViewRepresentableContext\u003cCalendarViewDisplayable\u003e) {\n        context.coordinator.events = events\n    }\n    \n    func makeCoordinator() -\u003e CalendarDisplayView.Coordinator {\n        Coordinator(self)\n    }\n    \n    public init(events: Binding\u003c[Event]\u003e) {\n        _events = events\n        calendar = KVKCalendarView(frame: frame, date: selectDate, style: style)\n    }\n    \n    // MARK: Calendar DataSource and Delegate\n    class Coordinator: NSObject, CalendarDataSource, CalendarDelegate {\n        private let view: CalendarViewDisplayable\n        \n        var events: [Event] = [] {\n            didSet {\n                view.events = events\n                view.calendar.reloadData()\n            }\n        }\n        \n        init(_ view: CalendarViewDisplayable) {\n            self.view = view\n            super.init()\n        }\n        \n        func eventsForCalendar(systemEvents: [EKEvent]) -\u003e [Event] {\n            events\n        }\n    }\n}\n```\n\nCreate a new `SwiftUI` file and add `CalendarViewDisplayable` to `body`.\n\n```swift\nimport SwiftUI\n\nstruct CalendarContentView: View {\n    @State var events: [Event] = []\n\n    var body: some View {\n        NavigationStack {\n            CalendarViewDisplayable(events: $events)\n        }\n    }\n}\n```\n\n## Styles\n\nTo customize calendar create an object `Style` and add to `init` class `CalendarView`.\n\n```swift\npublic struct Style {\n    public var event = EventStyle()\n    public var timeline = TimelineStyle()\n    public var week = WeekStyle()\n    public var allDay = AllDayStyle()\n    public var headerScroll = HeaderScrollStyle()\n    public var month = MonthStyle()\n    public var year = YearStyle()\n    public var list = ListViewStyle()\n    public var locale = Locale.current\n    public var calendar = Calendar.current\n    public var timezone = TimeZone.current\n    public var defaultType: CalendarType?\n    public var timeHourSystem: TimeHourSystem = .twentyFourHour\n    public var startWeekDay: StartDayType = .monday\n    public var followInSystemTheme: Bool = false \n    public var systemCalendars: Set\u003cString\u003e = []\n}\n```\n\n## Author\n\n[Sergei Kviatkovskii](https://github.com/kvyatkovskys)\n\n## License\n\nKVKCalendar is available under the [MIT license](https://github.com/kvyatkovskys/KVKCalendar/blob/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvyatkovskys%2Fkvkcalendar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkvyatkovskys%2Fkvkcalendar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvyatkovskys%2Fkvkcalendar/lists"}