How to tell if an EKEvent instance is declined or not? - swift

I have a list of EKEvent's for the current day, and I want to filter out any that have been declined by the current user so that the list only contains
How can I do this? I can't find any examples anywhere, or any property on the event itself to store this info.
Here's some sample code, if that helps:
let eventStore = EKEventStore()
let today = Date()
let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
let predicate = self.eventStore.predicateForEvents(withStart: today, end: tomorrow, calendars: nil)
let events = self.eventStore.events(matching: predicate)
// #TODO: Filter events by removing declined events.

you can get the infos via attendees and then participantStatus -> declined

Related

Swift: check if date is the same date as any day in array of dates?

I have an array of date objects - posts. And I am looping through a month. For each day, I want to check if some date in the array is on the same day. So far I have this:
var date = month?.startOfMonth()
var end = month?.endOfMonth()
while date! <= end! {
if posts.reduce(false,{Calendar.current.isDate(date, inSameDayAsDate: post.timeStamp)}) == true {
....
}
date = Calendar.current.date(byAdding: .day, value: 1, to: date!)
}
I believe that this starts with false and for each day in posts it checks whether its in the same day and if it is it turns the result into true. However I think it also changes it back to false the next time it encounters a false value...
What I want is something that returns true if any of the dates in posts is the same as some day rather than the last one. How can I do this?
Your current code is mostly OK though I would replace reduce with contains.
if let start = month?.startOfMonth(), let end = month?.endOfMonth() {
var date = start
var found = false
while !found && date <= end {
if posts.contains { Calendar.current.isDate(date, inSameDayAs: $0.timeStamp) } {
found = true
}
date = Calendar.current.date(byAdding: .day, value: 1, to: date)
}
if found {
// We have a match
}
}
I am basically building a stack view - for every day - I create a rectangle which is blue if there is a post that day and clear if not. Thus I probably do need to know the day. However filtering the array for elements which are in the specified month seems interesting. Can you show how to do that? Perhaps I could specify the location of just those days and then fill the rest of the stackArray with clear values using insertItem atIndex
Basically, I might start with two functions, one to filter the dates by month and one to filter by day. The reason I would so this, in your case, is you for each day, you don't want to refilter all the available dates for the month (but that's just me)
func dates(_ dates: [Date], withinMonth month: Int) -> [Date] {
let calendar = Calendar.current
let components: Set<Calendar.Component> = [.month]
let filtered = dates.filter { (date) -> Bool in
calendar.dateComponents(components, from: date).month == month
}
return filtered
}
func dates(_ dates: [Date], forDay day: Int) -> [Date] {
let calendar = Calendar.current
let components: Set<Calendar.Component> = [.day]
let filtered = dates.filter { (date) -> Bool in
calendar.dateComponents(components, from: date).day == day
}
return filtered
}
You could, use a contains approach, matching both the month and day, but again, there is an overhead to consider. In the above example, you could simply check to see if the day is contained in the resulting filtered dates by month, which might be closer to you desired result
nb This is not as efficient as something like first or contains as this will iterate the entire array finding every matching element, but, it has the nice side effect of providing you with more information. For example, you could sort the resulting filters and simply iterate from the start of the month to the end, popping off each match day as it occurs, as an idea
Thinking out loud...
Another approach might be to filter the available date's by the month, as above, but then to map the result to a Set of days (ie Int), this would allow you to either iterate over each day of the month and use contains(day) to perform a simple check to see if the day is contained or not.
Equally, you could map the view's to each day and iterate of the Set, changing the state of each view.
This all depends on more context then is available, but needless to say, there are any number of ways you might approach this problem
[Updated] As rightly mentioned already, you might be more interested in having a Set of days that have at least one post, something like:
let dayComponents: Set<Calendar.Component> = [.day, .month, .year, .era]
let calendar = Calendar.current
let daysWithPosts = Set(posts.map { post in
calendar.dateComponents(dayComponents, from: post.date)
})
Then for each date you can check if it's in that set (context unchanged, mind the force unwraps):
while date! <= end! {
let currentDayComponents = calendar.dateComponents(dayComponents, from: date)
let postsFound = daysWithPosts.contains(currentDayComponents)
// <use postsFound as needed>
date = Calendar.current.date(byAdding: .day, value: 1, to: date!)
}
Original answer, adapted for multiple dates:
This should tell if there are posts on a given date's day:
func areTherePosts(in posts: [Post], fromSameDayAs date: Date) -> Bool {
let calendar = Calendar.current
let dayComponents: Set<Calendar.Component> = [.day, .month, .year, .era]
let specificDateComponents = calendar.dateComponents(dayComponents, from: date)
return posts.contains { post in
calendar.dateComponents(dayComponents, from: post.date) == specificDateComponents
}
}
Usage in your context (again, unchanged):
while date! <= end! {
let postsFound = areTherePosts(in: posts, fromSameDayAs: date!)
// <use postsFound as needed>
date = Calendar.current.date(byAdding: .day, value: 1, to: date!)
}

Creating UILocalNotifications with CoreData attribute

In my iOS app I am trying to create a localNotification to notify the user 15 minutes prior to the event beginning. However I am stuck. I am using CoreData to store data. I have an Appointment object which can be created. A date attribute is associated with a Appointment object. I am really stuck with it. I do not know how to set up the timeInterval and the rest of the notification process.
I do not know how to set up the timeInterval from the time the Appointment is created to 15 minutes prior to when it begins.
Here is some of my code:
func scheduleNotifications() {
let content = UNMutableNotificationContent()
guard let client = client, let name = client.name, let formula = formula, let date = formula.date else { return }
content.title = "BookMe"
content.subtitle = ""
content.body = "Your appointment with \(name) will begin soon."
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: ??, repeats: false)
Edited: This is what I have but nothing is firing.
let date = formula.date
let fireDate = Calendar.current.date(byAdding: DateComponents(minute: -15), to: date as Date)
guard let timeInterval = fireDate?.timeIntervalSince(Date()) else { return }
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
let request = UNNotificationRequest(identifier: self.timerUserNotificationIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
As I understand it you are looking to find a time interval between right now and 15 minutes before some date so that you can fire a notification 15 minutes before that date.
Here's a quick example I knocked up in a playground
// Create a date in the future - this is what you get from your own data object and I'm creating it here just so I have a date.
let scheduledDate = Calendar.current.date(from: DateComponents(year: 2017, month: 09, day: 22, hour: 22))!
// Create a date 15 minutes earlier than your shcheduled date, this is when you want your notification to fire
let fireDate = Calendar.current.date(byAdding: DateComponents(minute: -15), to: scheduledDate)!
// Then just work out the time interval between the fire date and now to get the time interval
let timeInterval = fireDate.timeIntervalSince(Date())
Excuse the force unwrapping of the created dates, these are because it's an example, you should instead not use exclamation marks and handle errors gracefully.
edited to add
UNTimeIntervalNotificationTrigger, which you are trying to use requires a TimeInterval between now and the time you want to fire the notification. A TimeInterval is a Double that represents a number of seconds. In some cases, such as this one, it represents a delay, the number of seconds between now and the time you want to fire the the notification. In other cases it represents a date by the number of seconds from a fixed date. This fixed date is either timeIntervalSince1970 - "The interval between the date object and 00:00:00 UTC on 1 January 1970." Which is what you use for UNIX timestamps or timeIntervalSinceReferenceDate - "The interval between the date object and 00:00:00 UTC on 1 January 2001."
Whatever you do, resist the temptation to modify dates by adding or removing numbers of seconds directly, use DateComponents instead.

Constructing a date for getRequestedUpdateDateWithHandler:

I need to update my watchOS complication at midnight every day.
startOfDay is the beginning of the day (i.e., 12 AM today).
Should I add a day to the start of today like this?
func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) {
// Call the handler with the date when you would next like to be given the opportunity to update your complication content
let startOfDay = NSDate().startOfDay
let components = NSDateComponents()
components.day = 1
let startOfNextDay = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: startOfDay, options: NSCalendarOptions())
handler(startOfNextDay)
}
Or should I not add a day to the code, and just do something like this:
func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) {
// Call the handler with the date when you would next like to be given the opportunity to update your complication content
let startOfDay = NSDate().startOfDay
handler(startOfDay)
}
You'd want to advance the date one day, since you want your next requested update to occur at tomorrow's midnight. The first method would do what you want, but you can simplify it as follows:
let calendar = NSCalendar.currentCalendar()
let startOfDay = calendar.startOfDayForDate(NSDate())
let startOfNextDay = calendar.dateByAddingUnit(.Day, value: 1, toDate: startOfDay, options: NSCalendarOptions())!
The second code would return today's 12 AM, which would already be in the past.

How do I filter events created for the current date in the Realm swift?

How do I filter events created for the current date in the Realm swift?
I tried something like below but this wrong.
let dtSource = datasource.filter("Create == NSDate()").count
Update: Getting the filter creating my date as a string.
http://i.stack.imgur.com/8fLX9.png
http://i.stack.imgur.com/HDR2X.png
A query in the form of Create == NSDate() will check exact date equality, which will compare down to the second. If you want to check if a date is between a given interval, like checking if it's on a specific day, regardless of the time of day, you could do a BETWEEN check:
let dtSource = datasource.filter("Create BETWEEN %#", [firstDate, secondDate]).count
Update:
Here's a full code sample to get all date models for the current day:
import RealmSwift
class Event: Object {
dynamic var date = NSDate()
}
let todayStart = Calendar.current.startOfDay(for: Date())
let todayEnd: Date = {
let components = DateComponents(day: 1, second: -1)
return Calendar.current.date(byAdding: components, to: todayStart)!
}()
events = realm.objects(Event.self).filter("date BETWEEN %#", [todayStart, todayEnd])

Swift UIEventKit - creating an event for specific days

I am pretty new to swift, so I am just hoping someone could help me out - I am trying to use UIEventKit to add an event to the calendar (which I have figured out how to do) however there are two things that I am unsure about:
1 - I want to be able to add the event to the next instance of a particular day. eg. the next coming Monday
2 - I want to be able to have that event recurring on that day a certain number of times - lets say 4.
Any help anyone can offer on either of the above would be greatly appreciated!
Here's what i have so far:
func createEvent(eventStore: EKEventStore, title: String, startDate: NSDate, endDate: NSDate){
let event = EKEvent(eventStore: eventStore)
event.title = title
event.startDate = startDate
event.endDate = endDate
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.saveEvent(event, span: .ThisEvent)
}catch {
let alertView = UIAlertController(title: "Access Denied", message: "Please change your settings to allow us to access your calendar", preferredStyle: UIAlertControllerStyle.Alert)
alertView.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertView, animated: true, completion: nil)
}
}
#IBAction func addToCalendar(sender: UIButton) {
let eventStore = EKEventStore()
let startDate = NSDate()
let endDate = startDate.dateByAddingTimeInterval(60 * 30)
if (EKEventStore.authorizationStatusForEntityType(.Event) != EKAuthorizationStatus.Authorized) {
eventStore.requestAccessToEntityType(.Event, completion: {
granted, error in
self.createEvent(eventStore, title: "Psychology Lecture", startDate: startDate, endDate: endDate)
})
}else {
createEvent(eventStore, title: "Psychology Lecture", startDate: startDate, endDate: endDate)
}
}
I want to be able to add the event to the next instance of a particular day. eg. the next coming Monday
How are you handling the UI for the app? A best option for this kind of case would be to display the Date Picker - and let the user choose a date. And you can then create an event for that specific date.
I want to be able to have that event recurring on that day a certain number of times - lets say 4.
Here's the documentation for creating Recurring Events and it seems you cannot have an event recurring n times on a particular day.
I would suggest - creating the event with a different time or creating it an all day event.
For an all day event
event.allDay = true
For creating the event with a different time - I bumped up the day with different time
createEvent(eventStore, title: "Psychology Lecture", startDate: startDate, endDate: endDate)
//Bump up the time by 30 minutes
startDate = startDate.dateByAddingTimeInterval(60 * 30)
endDate = endDate.dateByAddingTimeInterval(60 * 30)
self.createEvent(eventStore, title: "Another Psychology Lecture", startDate: startDate, endDate: endDate)
Does this help?