2

I've created an appointment reminder app for customers but a few have said they would like the app to give them an earlier notification say one day in advance (24 hours) as well as at the time of the appointment, but I'm unsure how I can edit my code to do this.

Here is my working code that shows the appointment at the chosen time on the date picker:

import UIKit
import EventKit

class RemindersViewController: UIViewController {

    @IBOutlet weak var reminderText: UITextField!
    @IBOutlet weak var myDatePicker: UIDatePicker!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
    let appDelegate = UIApplication.shared.delegate
        as! AppDelegate

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    }

    @IBAction func setReminder(_ sender: AnyObject) {

        if reminderText.text == "" {

            // Create the alert controller
            let alertController = UIAlertController(title: "Information Needed", message: "Please type in your treatment and select the correct date and time you wish to be reminded about before pressing the Create Appointment Reminder button.", preferredStyle: .alert)

            // Create the actions
            let okAction = UIAlertAction(title: "Got It", style: UIAlertActionStyle.default) {
                UIAlertAction in
                NSLog("OK Pressed")
            }

            // Add the actions
            alertController.addAction(okAction)

            // Present the controller
            self.present(alertController, animated: true, completion: nil)

        } else {

            activityIndicator.startAnimating()

            let eventStore = EKEventStore()
            eventStore.requestAccess(
                to: EKEntityType.reminder, completion: {(granted, error) in
                    if !granted {
                        print("Access to store not granted")
                        print(error!.localizedDescription)
                    } else {
                        print("Access granted")
                        self.createReminder(in: eventStore)
                    }
            })
        }

        self.reminderText.resignFirstResponder()
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        textField.resignFirstResponder()

        return true
    }

    func createReminder(in eventStore: EKEventStore) {

        let reminder = EKReminder(eventStore: eventStore)

        reminder.title = reminderText.text! + " " + "(Pose Beauty Salon)"
        reminder.calendar =
            eventStore.defaultCalendarForNewReminders()
        let date = myDatePicker.date
        let alarm = EKAlarm(absoluteDate: date)

        reminder.addAlarm(alarm)

        do {
            try eventStore.save(reminder,
                                             commit: true)
        } catch let error  {
            print("Reminder failed with error \(error.localizedDescription)")
        }

        // Create the alert controller
        let alertController = UIAlertController(title: "Reminder Created Successfully", message: "Your \(reminderText.text!) appointment reminder at Pose Beauty Salon has been successfully created in your iPhone Reminders app.  Thank You!", preferredStyle: .alert)

        // Create the actions
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
            UIAlertAction in
            NSLog("OK Pressed")
            self.reminderText.text = ""
            self.activityIndicator.stopAnimating() 
        }

        // Add the actions
        alertController.addAction(okAction)

        // Present the controller
        self.present(alertController, animated: true, completion: nil)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        reminderText.endEditing(true)
    }
}

I've changed my code as follows but I only get the reminder saved once:

func createReminder(in eventStore: EKEventStore) {

    let reminder = EKReminder(eventStore: eventStore)
    let secondReminder = EKReminder(eventStore: eventStore)

    reminder.title = reminderText.text! + " " + "(Pose Beauty Salon)"
    reminder.calendar =
        eventStore.defaultCalendarForNewReminders()
    secondReminder.title = reminderText.text! + " Tomorrow " + "(Pose Beauty Salon)"
    secondReminder.calendar =
        eventStore.defaultCalendarForNewReminders()
   // let date = myDatePicker.date
    let actualDate = myDatePicker.date
    let earlyReminderDate = actualDate.addingTimeInterval(-3600*24)
    //let alarm = EKAlarm(absoluteDate: date)
    let alarm = EKAlarm(absoluteDate: actualDate)
    let secondAlarm = EKAlarm(absoluteDate: earlyReminderDate)

    reminder.addAlarm(alarm)
    secondReminder.addAlarm(secondAlarm)
halfer
  • 19,824
  • 17
  • 99
  • 186
Elfuthark
  • 261
  • 1
  • 4
  • 17

2 Answers2

3

It seems that eventStore.defaultCalendarForNewReminders() doesn't allow for multiple alarms.

You can achieve this behaviour if you save the reminder to the calendar app instead.

I made some changes to your code to do this, hopefully this is useful: Updated the access request

let eventStore = EKEventStore()
        eventStore.requestAccess(
            to: EKEntityType.event, completion: {(granted, error) in
                if !granted {
                    print("Access to store not granted")
                    print(error!.localizedDescription)
                } else {
                    print("Access granted")
                    self.createReminder(in: eventStore)
                }
        })

Create an EKEvent instead of EKReminder and open the EKEventEditViewController

func createReminder(in eventStore: EKEventStore) {

    let reminder = EKEvent(eventStore: eventStore)

    reminder.title = reminderText.text! + " " + "(Pose Beauty Salon)"
    reminder.calendar =
        eventStore.defaultCalendarForNewEvents
    let date = myDatePicker.date
    let alarm = EKAlarm(absoluteDate: date)
    reminder.addAlarm(alarm)

    let earlierDate = date.addingTimeInterval(-3600*24)
    let earlierAlarm = EKAlarm(absoluteDate: earlierDate)
    reminder.addAlarm(earlierAlarm)

    reminder.startDate = date
    reminder.endDate = date.addingTimeInterval(3600)

    do {
        try eventStore.save(reminder, span: .thisEvent, commit: true)
    } catch let error  {
        print("Reminder failed with error \(error.localizedDescription)")
        return
    }


    // Create the alert controller
    let alertController = UIAlertController(title: "Reminder Created Successfully", message: "Your \(reminderText.text!) appointment reminder at Pose Beauty Salon has been successfully created in your iPhone Reminders app.  Thank You!", preferredStyle: .alert)

    // Create the actions
    let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
        UIAlertAction in
        NSLog("OK Pressed")
        self.reminderText.text = ""
        self.activityIndicator.stopAnimating()
    }

    // Add the actions
    alertController.addAction(okAction)

    // Present the controller
    self.present(alertController, animated: true, completion: nil)


}

Added delegate method from EKEventEditViewDelegate

func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {

    switch action
    {
    case .saved:
        let alertController = UIAlertController(title: "Reminder Created Successfully", message: "Your \(reminderText.text!) appointment reminder at Pose Beauty Salon has been successfully created in your iPhone Reminders app.  Thank You!", preferredStyle: .alert)

        // Create the actions
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
            UIAlertAction in
            NSLog("OK Pressed")
            self.reminderText.text = ""
            self.activityIndicator.stopAnimating()
        }

        // Add the actions
        alertController.addAction(okAction)

        // Present the controller
        self.present(alertController, animated: true, completion: nil)

    default:
        self.dismiss(animated: true, completion: nil)
    }

}
darrenallen7
  • 821
  • 4
  • 9
  • Hi @darrenallen7 I'd never worked with calendars before and this is actually what I'd prefer to use so this is great thanks, I have amended my code to yours with a few errors hopefully you can help me with the first was the line: let eventController = EKEventEditViewController() not sure if I was correct to change this to eventEditViewController() and the next error I'm unsure how to fix is use of undeclared type EKEventEditViewAction If we can get this sorted I'll be one happy Chappy :) – Elfuthark May 27 '17 at 13:54
  • Hi @Futhark, sorry you need to add `import EventKitUI` at the top of the file. Also the class declaration needs to change: `class RemindersViewController: UIViewController, EKEventEditViewDelegate` – darrenallen7 May 27 '17 at 14:23
  • That was my fault I should have noticed I had EventKit and not EventKitUI imported lol, this is almost working as expected, Im not sure if it is possible or not so need to ask you @darrenallen7 when I click the button to create the reminder it opens up my calendar app and it fills in the new event title from my code and sets the two alarms correct at the bottom and then I have to hit the add button twice for some reason but I had hoped this was all done in the background of my app with just my alert saying it had been successfully added to the calendar, is that possible? – Elfuthark May 27 '17 at 14:52
  • @Futhark I have updated the `createReminder(in eventStore: EKEventStore) ` method in my answer to do this. It actually uses most of the code you had for saving a reminder. I have added a return to your try catch to prevent the successful alert displaying even if there is an error. You probably don't need the EKEventKitUI import anymore or the `didCompleteWith...` method. – darrenallen7 May 27 '17 at 15:05
0

You could create two separate reminders with all same data but with different dates like this:

let actualDate = myDatePicker.date
let earlyReminderDate = actualDate.addingTimeInterval(-3600*24)
badhanganesh
  • 3,427
  • 3
  • 18
  • 39
  • Thanks for the reply @Badhan I've edited my post above to show you how I've edited my code to do like you said but had to change the syntax slightly but I still only get one entry in the reminders app, do you know what I might have done wrong here? – Elfuthark May 27 '17 at 13:21