Code Monkey home page Code Monkey logo

calendarapp's People

Contributors

richardtop avatar sp4ce-cowboy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

calendarapp's Issues

Restart needed after granted calendar access to display events

Hi, i am using the latest CK Version. When i start my app the first time, i granted the permission to access my calendar. But after that, CalendarKit is not able to display events. I try to call reloadData() in requestAccessToCalendar() but with now success.

What do i need to change to display events after request access without starting the app again?

ekEvent

When I was compiling this project, it said "Cannot find 'ekEvent' in scope"
The error happened in the line 74 of the "CalenderViewController". How can I fix the problems about the event kit. Please help me out. Thank you very much.

New API available for EventKit

https://developer.apple.com/documentation/technotes/tn3152-migrating-to-the-latest-calendar-access-levels

In IOS 17, a new API is used for calendar Event store access. Code needs to add in logic to detect that in CalendarViewController. The new API call is eventStore.requestFullAccessToEvents. You will also need to add in a new reference in the plist for full access. Privacy - Calendar Full Access Usage Description

private func requestAccessToCalendar() {

    do {

        if #available(iOS 17.0, *) {
            eventStore.requestFullAccessToEvents { [weak self] granted, error in
                DispatchQueue.main.async {
                    guard let self else { return }
                    self.initializeStore()
                    self.subscribeToNotifications()
                    self.reloadData()
                }             
        }

        } else {

            eventStore.requestAccess(to: .event) { [weak self] granted, error in
                // Handle the response to the request.
                DispatchQueue.main.async {
                    guard let self else { return }
                    self.initializeStore()
                    self.subscribeToNotifications()
                    self.reloadData()
                }
            }
        }
    }
}

Crash

Hi @richardtop I found a bug (maybe not) when I add invitee from ios calendar and go to calenderkit view and click that event app directly crashes or when I click add invitee in the app in calender kit view it directly crashes. Is there a way to solve it or a way to remove that section that says add invitee? Even I remove the add invitee in the calender kit view if a user has added an invitee from ios calender it will keep crushing. do you have a solution for that? Any document or walktrough video smth?

`
import UIKit
import CalendarKit
import EventKit
import EventKitUI
import Firebase
import FirebaseAuth

class BsCalendarViewController: DayViewController, EKEventEditViewDelegate {

private let eventStore =  EKEventStore()

let db = Firestore.firestore()
let currentUserMail = Auth.auth().currentUser?.email
var xx = ""

override func viewDidLoad() {
    super.viewDidLoad()
    requestAccessToCalendar()
    subscribeToNotifications()
    getCurrentUserData()
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: self.uploadCurrentUserCalendar)
    
    let appearance = UINavigationBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.shadowColor = nil
    
    let navigationBar = navigationController!.navigationBar
    navigationBar.standardAppearance = appearance
    navigationBar.scrollEdgeAppearance = appearance
    
    self.navigationController?.setToolbarHidden(true, animated: false)

}

func getCurrentUserData() {
    
    db.collection("xx").document(xx!).getDocument { (document, error) in
        
        if let document = document, document.exists {
               let dataDescription = document.data()
            guard let type = dataDescription?["x x"] else {return}
            self.xx = type as! String
           } else {
               print("Document does not exist")
           }
    }
}

var eventBox: [EventBox] = []

func uploadCurrentUserCalendar() {
    
    self.db.collection(xx).document(xx!).collection("Calendar").getDocuments() { (querySnapshot, err) in
        if let err = err {
            let alert = UIAlertController(title: "Upload Error", message: err.localizedDescription, preferredStyle: UIAlertController.Style.alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
            self.present(alert, animated: true, completion: nil)
            return
        } else {
            for document in querySnapshot!.documents {
                document.reference.delete()
            }
            let startDate = Calendar.current.date(byAdding: .day, value: -7, to: Date())
            
            var oneDayComponents = DateComponents()
            oneDayComponents.day = 35
            let endDate = self.calendar.date(byAdding: oneDayComponents, to: startDate!)!
            let predicate = self.eventStore.predicateForEvents(withStart: startDate!, end: endDate, calendars: nil)
            let eventKitEvents = self.eventStore.events(matching: predicate)
        
            for event in eventKitEvents {
               if let startDate = event.startDate,
                  let endDate = event.endDate,
                  let isAllDay = event.isAllDay as? Bool,
                  let title = event.title{
                   let newEventBox = EventBox(startDate: startDate, endDate: endDate, isAllDay: isAllDay, title: title)
                   self.eventBox.append(newEventBox)

               }
            }
            for uploadData in self.eventBox {
                self.db.collection(x.xx).document(x.xx!).collection("Calendar").document(uploadData.title).setData([ "title" : uploadData.title, "startDate" : uploadData.startDate, "endDate" : uploadData.endDate, "isAllDay" : uploadData.isAllDay])
            }
        }
    }
    

}


override func viewWillDisappear(_ animated: Bool) {
    self.navigationController?.setToolbarHidden(true, animated: false)

}
override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.setToolbarHidden(true, animated: false)

}

func subscribeToNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(storeChanged(_:)), name: .EKEventStoreChanged, object: nil)
}

@objc func storeChanged(_ notification: Notification) {
    reloadData()
    uploadCurrentUserCalendar()
}


func requestAccessToCalendar() {
    
    eventStore.requestAccess(to: .event) { success, error in
        
    }
}


override func eventsForDate(_ date: Date) -> [EventDescriptor] {
    
    let startDate = date
   
    var oneDayComponents = DateComponents()
    oneDayComponents.day = 1
   
    let endDate = calendar.date(byAdding: oneDayComponents, to: startDate)!
   
    let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
   
    let eventKitEvents = eventStore.events(matching: predicate)
    let calenderKitEvents = eventKitEvents.map(EKWrapper.init)

    return calenderKitEvents
}

override func dayViewDidSelectEventView(_ eventView: EventView) {
    
    guard let ckEvent = eventView.descriptor as? EKWrapper else {
        return
    }
    
    let ekEvent = ckEvent.ekEvent
    presentDetailView(ekEvent)
}

private func presentDetailView(_ ekEvent: EKEvent) {
    
    let eventViewController = EKEventViewController()
    eventViewController.event = ekEvent
    eventViewController.allowsCalendarPreview = true
    eventViewController.allowsEditing = true
    navigationController?.pushViewController(eventViewController, animated: true)
}

override func dayViewDidLongPressEventView(_ eventView: EventView) {
    endEventEditing()
    guard let ckEvent = eventView.descriptor as? EKWrapper else { return }
    
    beginEditing(event: ckEvent, animated: true)
}


override func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
    guard let editingEvent = event as? EKWrapper else { return }
    if let originalEvent = event.editedEvent {
        editingEvent.commitEditing()
        
        if originalEvent === editingEvent {
            // event creation flow
            presentEditingViewForEvent(editingEvent.ekEvent)
        } else {
            // editing flow
            try! eventStore.save(editingEvent.ekEvent, span: .thisEvent)
        }
        
        
    }
    reloadData()
}

func presentEditingViewForEvent(_ ekEvent: EKEvent) {
    let editingViewController = EKEventEditViewController()
    editingViewController.editViewDelegate = self
    editingViewController.event = ekEvent
    editingViewController.eventStore = eventStore
    present(editingViewController, animated: true, completion: nil)
}

override func dayView(dayView: DayView, didTapTimelineAt date: Date) {
    endEventEditing()
}

override func dayViewDidBeginDragging(dayView: DayView) {
    endEventEditing()
}

override func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
    let newEKEvent = EKEvent(eventStore: eventStore)
    newEKEvent.calendar = eventStore.defaultCalendarForNewEvents
    
    var oneHourComponents = DateComponents()
    oneHourComponents.hour = 1
    
    let endDate = calendar.date(byAdding: oneHourComponents, to: date)
    
    newEKEvent.startDate = date
    newEKEvent.endDate = endDate
    newEKEvent.title = "New Event"
    
    let newEKWrapper = EKWrapper(eventKitEvent: newEKEvent)
    newEKWrapper.editedEvent = newEKWrapper
    
    create(event: newEKWrapper, animated: true)
}

func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
    endEventEditing()
    reloadData()
    controller.dismiss(animated: true, completion: nil)
}

}`

RecordIt-1660979196.MP4

Calendar View

Hi Richard,

is it possible to use your Tool and the provided Program to program an app that looks like the Samsung calender or like the Ipad calendar but on the iphone. I really like the ipad calendar look but also want to have it on the ipad.

image

Best wishes
Christopher

got nil when try to open event

when press on event I got nil as he can't cast from EventDescriptor to EkWrapper any help please `
//
// CalendarViewController.swift
// Servbud provider
//
// Created by Khaled on 22/12/2021.
// Copyright ยฉ 2021 ORGANIZATIONNAME. All rights reserved.
//

import UIKit
import CalendarKit
import EventKit
import EventKitUI
import LKAlertController

protocol CalendarDisplayLogic: AnyObject {
func displayAvailableTimes(times: [[MainNetworkModels.AvailableTimes]])
func displayError(errorMessage: String)
func displayUnAuthorized()
}

class CalendarViewController: DayViewController, CalendarDisplayLogic, EKEventEditViewDelegate {

// MARK: - Properties

typealias Models = CalendarModels
var router: (NSObjectProtocol & CalendarRoutingLogic & CalendarDataPassing)?
var interactor: CalendarBusinessLogic?
private var eventStore =  EKEventStore()
let apiDate = DateFormatter()
let currentDate = Calendar.current.dateComponents([.year, .month], from: Date())
var currentmonth = Calendar.current.dateComponents([.year, .month], from: Date()).month
var allTimes: [MainNetworkModels.AvailableTimes] = []
var events = [Event]()

// MARK: - Object lifecycle

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    setup()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
}

// MARK: - Setup

private func setup() {
    let viewController = self
    let interactor = CalendarInteractor()
    let presenter = CalendarPresenter()
    let router = CalendarRouter()

    viewController.router = router
    viewController.interactor = interactor
    interactor.presenter = presenter
    presenter.viewController = viewController
    router.viewController = viewController
}

// MARK: - View Lifecycle

override func viewDidLoad() {
    super.viewDidLoad()
    apiDate.dateFormat = "yyyy-MM-dd HH:mm:ss"
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    setupUI()
    requestAccessToCalendar()
    view.showActivityView()
    interactor?.getAvailableTimes(month: String(currentDate.month ?? 1), year: String(currentDate.year ?? 2022))
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    events.removeAll()
    allTimes.removeAll()
}

func setupUI(){
    title = "My Calender"
}

private func requestAccessToCalendar() {
    // Request access to the events
    eventStore.requestAccess(to: .event) { [weak self] granted, error in
        // Handle the response to the request.
        DispatchQueue.main.async {
            guard let self = self else { return }
            self.initializeStore()
            self.reloadData()
        }
    }
}

private func initializeStore() {
    eventStore = EKEventStore()
}

override func eventsForDate(_ date: Date) -> [EventDescriptor] {
    events.removeAll()
    allTimes.forEach { time in
        let fromStringString = (time.from?.date ?? "") + " " + (time.from?.time ?? "")
        let toStringString = (time.to?.date ?? "") + " " + (time.to?.time ?? "")
        let newEvent = Event()
        newEvent.dateInterval = DateInterval(start: apiDate.date(from: fromStringString) ?? Date(), end: apiDate.date(from: toStringString) ?? Date())
        newEvent.isAllDay = false
        newEvent.color = .random
        newEvent.backgroundColor = .random
        newEvent.text = "Avabilty \n from: " + (time.from?.time ?? "") + "to: " + (time.to?.time ?? "")
        newEvent.textColor = .white
        events.append(newEvent)
    }
    return events
}

// MARK: - DayViewDelegate

// MARK: Event Selection

override func dayViewDidSelectEventView(_ eventView: EventView) {
    guard let ckEvent = eventView.descriptor as? EKWrapper else {
        return
    }
    presentDetailViewForEvent(ckEvent.ekEvent)
}

private func presentDetailViewForEvent(_ ekEvent: EKEvent) {
    let eventController = EKEventViewController()
    eventController.event = ekEvent
    eventController.allowsCalendarPreview = true
    eventController.allowsEditing = true
    navigationController?.pushViewController(eventController,
                                             animated: true)
}

// MARK: Event Editing

override func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
    // Cancel editing current event and start creating a new one
    endEventEditing()
    let newEKWrapper = createNewEvent(at: date)
    create(event: newEKWrapper, animated: true)
}

private func createNewEvent(at date: Date, to endDate: Date) -> EKWrapper {
    let newEKEvent = EKEvent(eventStore: eventStore)
    newEKEvent.calendar = eventStore.defaultCalendarForNewEvents
    newEKEvent.startDate = date
    newEKEvent.endDate = endDate
    newEKEvent.title = "Availabilty"
    let newEKWrapper = EKWrapper(eventKitEvent: newEKEvent)
    newEKWrapper.editedEvent = newEKWrapper
    return newEKWrapper
}

private func createNewEvent(at date: Date) -> EKWrapper {
    let newEKEvent = EKEvent(eventStore: eventStore)
    newEKEvent.calendar = eventStore.defaultCalendarForNewEvents
    
    var components = DateComponents()
    components.hour = 1
    let endDate = calendar.date(byAdding: components, to: date)
    
    newEKEvent.startDate = date
    newEKEvent.endDate = endDate
    newEKEvent.title = "Availabilty"
    
    let newEKWrapper = EKWrapper(eventKitEvent: newEKEvent)
    newEKWrapper.editedEvent = newEKWrapper
    return newEKWrapper
}

override func dayViewDidLongPressEventView(_ eventView: EventView) {
    guard let descriptor = eventView.descriptor as? EKWrapper else {
        return
    }
    endEventEditing()
    beginEditing(event: descriptor, animated: true)
}

override func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
    guard let editingEvent = event as? EKWrapper else { return }
    if let originalEvent = event.editedEvent {
        editingEvent.commitEditing()
        
        if originalEvent === editingEvent {
            presentEditingViewForEvent(editingEvent.ekEvent)
        } else {
            
        }
    }
    events.removeAll()
    reloadData()
}


private func presentEditingViewForEvent(_ ekEvent: EKEvent) {
    let eventEditViewController = EKEventEditViewController()
    eventEditViewController.event = ekEvent
    eventEditViewController.eventStore = eventStore
    eventEditViewController.editViewDelegate = self
    present(eventEditViewController, animated: true, completion: nil)
}

override func dayView(dayView: DayView, didTapTimelineAt date: Date) {
    endEventEditing()
}

override func dayViewDidBeginDragging(dayView: DayView) {
    endEventEditing()
}

// MARK: - EKEventEditViewDelegate

func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
    endEventEditing()
    events.removeAll()
    reloadData()
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    let startDate = dateFormatter.string(from: controller.event?.startDate ?? Date())
    dateFormatter.dateFormat = "HH:mm"
    let startTime = dateFormatter.string(from: controller.event?.startDate ?? Date())
    let endTime = dateFormatter.string(from: controller.event?.endDate ?? Date())
    let sameEventsDay = allTimes.filter { event in
        return event.from?.date == startDate
    }
    var availableTimes = sameEventsDay.map { event -> CalendarModels.availabelTimes in
        let eventFormatter = DateFormatter()
        eventFormatter.dateFormat = "HH:mm:ss"
        let from = dateFormatter.string(from: eventFormatter.date(from: event.from?.time ?? "") ?? Date())
        let to = dateFormatter.string(from: eventFormatter.date(from: event.to?.time ?? "") ?? Date())
        return CalendarModels.availabelTimes(date: event.from?.date, from: from, to: to)
    }
    view.showActivityView()
    if action.rawValue == 1 {
        availableTimes.append(CalendarModels.availabelTimes(date: startDate, from: startTime, to: endTime))
    }
    interactor?.setAvailableTimes(availableTime: availableTimes)
    controller.dismiss(animated: true, completion: nil)
}

func displayAvailableTimes(times: [[MainNetworkModels.AvailableTimes]]){
    view.hideActivityView()
    allTimes.removeAll()
    times.forEach { item in
        allTimes.append(contentsOf: item)
    }
    events.removeAll()
    reloadData()
}

func displayError(errorMessage: String) {
    view.hideActivityView()
    showAlert(errorMessage: errorMessage, completion: nil)
}

func showAlert(errorMessage: String, completion: (( _ choose: Bool) -> Void)?){
    Alert(title: "error", message: errorMessage)
        .addAction("ok", style: .default) { _ in
            completion?(true)
        }
        .show()
}

func displayUnAuthorized(){
    SharedPrefrences.shared.deconnectUSer()
    router?.goToLogin()
}

override func dayView(dayView: DayView, willMoveTo date: Date){
    let calendarDate = Calendar.current.dateComponents([.year, .month], from: date)
    if (calendarDate.month != currentmonth) {
        events.removeAll()
        allTimes.removeAll()
        view.showActivityView()
        interactor?.getAvailableTimes(month: String(calendarDate.month ?? 1), year: String(calendarDate.year ?? 2022))
        currentmonth = calendarDate.month
    }
}

}

`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.