Skip to content

Instantly share code, notes, and snippets.

@zats
Created April 7, 2018 21:08
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zats/4a8b365be47648d08aff7d43dff363be to your computer and use it in GitHub Desktop.
Save zats/4a8b365be47648d08aff7d43dff363be to your computer and use it in GitHub Desktop.
This is a sample of how to add actionable button for Reminders (private API); demo video: https://youtu.be/q7LrO3VhI64
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let reminderListName = "Test"
import EventKit
extension EKCalendarItem {
var hack_action: AnyObject? {
set {
setValue(newValue, forKey: "action")
}
get {
return value(forKey: "action") as AnyObject?
}
}
}
let modifier: (EKReminder) -> Void = { reminder in
guard let title = reminder.title else {
return
}
if let action = reminder.hack_action, !(action is NSNull) {
print("Action for reminder \"\(title)\" already set to \"\(action)\"")
return
}
let types: NSTextCheckingResult.CheckingType = [.address, .phoneNumber, .link, .date]
let detector = try! NSDataDetector(types: types.rawValue)
let range = NSRange(location: 0, length: title.count)
let results = detector.matches(in: title, options: [], range: range)
guard let result = results.first else {
return
}
let match = String(title[title.index(title.startIndex, offsetBy: result.range.location)
..<
title.index(title.startIndex, offsetBy: NSMaxRange(result.range))])
if result.resultType == .phoneNumber {
let phone = match.filter { CharacterSet.decimalDigits.contains(UnicodeScalar("\($0)")!) }
print("Updating phone number: \(phone)")
reminder.hack_action = URL(string: "tel://\(phone)") as AnyObject
} else if result.resultType == .address {
let address = match.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlFragmentAllowed)!
print("Upading address \"\(match)\"")
reminder.hack_action = URL(string: "https://maps.apple.com?address=\(address)") as AnyObject?
} else if result.resultType == .link {
print("Updating url: \(match)")
reminder.hack_action = URL(string: match) as AnyObject
}
}
func fetchAllReminders(for store: EKEventStore) {
let targetCalendar = store.calendars(for: .reminder).first(where: { $0.title == reminderListName })!
let predicate = store.predicateForIncompleteReminders(withDueDateStarting: nil, ending: nil, calendars: [targetCalendar])
store.fetchReminders(matching: predicate) { reminders in
guard let reminders = reminders else {
assertionFailure("No reminders found")
return
}
if reminders.isEmpty {
print("No reminders passed the filter")
return
}
for reminder in reminders {
modifier(reminder)
do {
try store.save(reminder, commit: false)
} catch {
fatalError("Failed to save reminder \(reminder.title): \(error)")
}
}
do {
try store.commit()
} catch {
fatalError("failed to save reminders \(error)")
}
print("Saved")
}
}
let store = EKEventStore()
store.requestAccess(to: .reminder) { result, error in
if let error = error {
assertionFailure("\(error)")
}
if (result) {
fetchAllReminders(for: store)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment