Swift- Pushing notifications at a user selected time - swift

How can I make a user choose a time by using a date picker and then send the user a local notification?

here is a simple code to schedule a local notification in swift:
let calendar: NSCalendar = NSCalendar.currentCalendar()
let fireDateOfNotification: NSDate = //The date which was picked from the picker
var notification = UILocalNotification()
notification.timeZone = NSTimeZone.localTimeZone()
notification.alertBody = "ALERT STRING"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = fireDateOfNotification
notification.userInfo = ["UUID": "NotificationID"] //id for the local notification in case you want to cancel it
UIApplication.sharedApplication().scheduleLocalNotification(notification)
and if you want to cancel a local notification you should use the following function:
func cancelLocalNotificationsWithUUID(uuid: Int) {
for item in UIApplication.sharedApplication().scheduledLocalNotifications {
let notification = item as! UILocalNotification
if let notificationUUID = notification.userInfo?["UUID"] as? Int {
if notificationUUID == uuid {
UIApplication.sharedApplication().cancelLocalNotification(notification)
}
}
}
}
I hope this helps.

Related

Adding EKRecurrenceRule to a Reminder not working (Creating a Recurring Event Issue)

I have a function that adds a new reminder. In this function, the reminder will have a reminder title and an alarm for a specific day and time.
The function currently looks like this:
var eventStore = EKEventStore()
var reminders = [EKReminder]()
func addReminder(date: Date, reminderTitle: String) {
eventStore.requestAccess(to: EKEntityType.reminder, completion: {
granted, error in
if (granted) && (error == nil) {
let reminder:EKReminder = EKReminder(eventStore: self.eventStore)
reminder.title = reminderTitle
let alarmTime = date
let alarm = EKAlarm(absoluteDate: alarmTime)
reminder.addAlarm(alarm)
reminder.calendar = self.eventStore.defaultCalendarForNewReminders()
do {
try self.eventStore.save(reminder, commit: true)
} catch {
print("Cannot save")
return
}
print("Reminder saved")
}
})
}
Now, I would like to add an EKRecurrenceRule that will repeat the alarm/reminder on a weekly basis forever (without a specific end date).
For a better explanation, this is the example of how I want my reminder to look in the end: Example
This is the approach I have already tried:
let recurrenceRule = EKRecurrenceRule(recurrenceWith: .weekly, interval: 1, daysOfTheWeek: [EKRecurrenceDayOfWeek(.monday)], daysOfTheMonth: nil, monthsOfTheYear: nil, weeksOfTheYear: nil, daysOfTheYear: nil, setPositions: nil, end: nil)
reminder.addRecurrenceRule(recurrenceRule)
Basically this should repeat the reminder every Monday, but for some reason, I cannot save the reminder.
Any help on how to successfully save a reminder?
SOLUTION: In order to have a working recurring event/reminder, the reminder needs to have a defined due date.
if(reminder.recurrenceRules?.count ?? 0 > 0 && reminder.dueDateComponents == nil) {
let calendar = Calendar.current
let components = calendar.dateComponents([Calendar.Component.day, Calendar.Component.month, Calendar.Component.year], from: date)
reminder.dueDateComponents = components
}

Swift changed DatePicker Date to Firebase

In my app, you click a button and the activity name and activity location is added to Firebase. I also want to add a selected time that you will be doing the activity to Firebase as well. To do this, I have created a DatePicker to pop up upon clicking the button, I have also managed to convert this to a string and upload to Firebase.
The issue I am having is the time that it uploads to Firebase is always the current time, am I right in saying I need to add an action to the DatePicker which will allow the selected time to be uploaded? If so how do I go about this?
func handleAddAgenda(){
var datePicker: UIDatePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePickerMode.DateAndTime
//datePicker.addTarget(self, action: #selector(dateChanged), forControlEvents: UIControlEvents.ValueChanged)
datePicker.frame = CGRectMake(0, 0, 250, 460)
datePicker.backgroundColor = UIColor.whiteColor()
addSubview(datePicker)
class ActDate: NSObject {
var date: String?
}
var actDate: ActDate?
if actDate == nil {
actDate = ActDate()
}
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "hh:mm a"
actDate?.date = dateFormatter.stringFromDate(datePicker.date)
print(datePicker.date)
let userID = FIRAuth.auth()?.currentUser?.uid
let ref = FIRDatabase.database().reference().child("users").child(userID!).child("Agenda")
let childRef = ref.childByAutoId()
let values = ["activity": activityName.text!, "location": distance.text!, "date": actDate!.date!]
childRef.updateChildValues(values)
}
Yes, you need to add some action method to update the values when the datePicker date is selected. This will only work of course if you make the date picker a property of the whole class in order to grab the datePicker.date in the new method.
Something like this in viewDidLoad:
datePicker.datePickerMode = UIDatePickerMode.DateAndTime
datePicker.frame = CGRectMake(0, 0, 250, 460)
datePicker.backgroundColor = UIColor.whiteColor()
myDatePicker.addTarget(self, action: #selector(dateChanged), for: .valueChanged)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "hh:mm a"
actDate?.date = dateFormatter.stringFromDate(datePicker.date)
Then you can have your handleAgenda simplified to this:
func handleAddAgenda(){
addSubview(datePicker)
print(datePicker.date)
}
And finally make the FireBase updates in the method:
func dateChanged() {
if let userID = FIRAuth.auth()?.currentUser?.uid {
let ref = FIRDatabase.database().reference().child("users").child(userID).child("Agenda")
let childRef = ref.childByAutoId()
if let activityName = activityName.text, let distance = distance.text, let date = datePicker.date {
let values = ["activity": activityName, "location": distance, "date": date]
childRef.updateChildValues(values)
}
}
}

how to make daily local notification depending on specific time in CVcalendar?

I am using cvcalendar and there is in everyday a different times for fajer, dohor , aser , maghreb , ishaa . for example i have selected the Adan for Fajer, so i want to get the adan in everyday and everyday has a different time. so when i get a notification in DidreceivedLocalNotification i want go to next day in calendar and get the time of the next day, knowing that am getting the times from CoreData .
in viewWillappear
let date = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
let calendar = NSCalendar.currentCalendar()
let calendarForDate = NSCalendar.currentCalendar()
let componentsForDate = calendar.components([.Day , .Month , .Year], fromDate: date)
let year = componentsForDate.year
let month = componentsForDate.month
let day = componentsForDate.day
//////////
//// Conditions after selecting the user (vibration, beep, Adan ) these conditions are testing the selected choice to send a notification to the user on his choice
//
if prayerCommingFromAdan.id == 0 && prayerCommingFromAdan.ringToneId != 0{
notificationId.id = 0
let hours = prayer0.time[0...1]
let minutes = prayer0.time[3...4]
let fajerTime = "\(month)-\(day)-\(year) \(hours):\(minutes)"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy hh:mm"
dateFormatter.timeZone = NSTimeZone.localTimeZone()
// convert string into date
let dateValue = dateFormatter.dateFromString(fajerTime) as NSDate!
var dateComparisionResult:NSComparisonResult = NSDate().compare(dateValue)
if dateComparisionResult == NSComparisonResult.OrderedAscending
{
addNotificationAlarm(year, month: month, day: day, hour: prayer0.time[0...1], minutes: prayer0.time[3...4], soundId: prayerCommingFromAdan.ringToneId, notificationBody: "It is al fajr adan")
}
What should i do in DidreceivedLocalNotification in AppDelegate?
You can use this code for scheduling your daily notifications according to time.
func ScheduleMorning() {
let calendar: NSCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
var dateFire=NSDate()
var fireComponents = calendar.components([.Hour, .Minute, .Second], fromDate: dateFire)
if (fireComponents.hour >= 7) {
dateFire=dateFire.dateByAddingTimeInterval(86400) // Use tomorrow's date
fireComponents = calendar.components([.Hour, .Minute, .Second], fromDate: dateFire)
}
fireComponents.hour = 7
fireComponents.minute = 0
fireComponents.second = 0
// Here is the fire time you can change as per your requirement
dateFire = calendar.dateFromComponents(fireComponents)!
let localNotification = UILocalNotification()
localNotification.fireDate = dateFire // Pass your Date here
localNotification.alertBody = "Your Message here."
localNotification.userInfo = ["CustomField1": "w00t"]
localNotification.repeatInterval = NSCalendarUnit.Day
UIApplication.sharedApplication().scheduleLocalNotification(localNotification) }
for receiving
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
// Do something serious in a real app.
print("Received Local Notification:")
print(notification.userInfo)
}

trying to combine two dates causes app to crash

I'm trying to trigger notification on specific saved time in database and on specific day which is Friday as shown below, but every time I try to save new reminder it tells me unexpectedly found nil while unwrapping an Optional value and I'm sure it contains data and it's not nil even though I tried to handle nil, still the app crash, however when I try to fire notification without combining dates like this localNotification.fireDate = reminders.time! the app is not crashed and it works just fine.
I guess the problem in combineDate function, how I can solve this problem?
func combineDate(time: NSDate?) -> NSDate{
let gregorianCalendar: NSCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let time: NSDateComponents = gregorianCalendar.components([.Hour, .Minute, .Second], fromDate: time!)
time.timeZone = NSTimeZone.systemTimeZone()
let timeCombiner: NSDateComponents = NSDateComponents()
timeCombiner.timeZone = NSTimeZone.systemTimeZone()
timeCombiner.hour = time.hour
timeCombiner.minute = time.minute
timeCombiner.second = 00
timeCombiner.weekday = 6
let combinedDate: NSDate = gregorianCalendar.dateFromComponents(components3)!
return combinedDate
}
func createLocalNotification(){
let localNotification = UILocalNotification()
localNotification.timeZone = NSTimeZone.systemTimeZone()
localNotification.fireDate = combineDate(reminders.time!)
localNotification.alertBody = reminders.name!
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
still the reason of causing all this mass unknown however I solved it by checking if reminder managed object is not equal to nil then try to fire notification
func createLocalNotification(){
let localNotification = UILocalNotification()
localNotification.timeZone = NSTimeZone.systemTimeZone()
if reminder != nil{
localNotification.fireDate = combineDate(reminders.time!)
}
localNotification.alertBody = reminders.name!
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}

First scheduleLocalNotification not being sent

I have an set of Local Notifications that I have scheduled to be sent out by setting a fire date on each one from iterating through an array. The problem is for some reason the first notification is not being sent, all the others are set and sent fine. This is the code:
var notifi = 0
var firstDate = NSDate()
let dateArrays = Array(1...3)
for _ in dateArrays{
if notifi < 64 {
firstDate = firstDate.dateByAddingTimeInterval(10)
notification.category = "FIRST_CATEGORY"
notification.alertBody = "It's time to look away now!"
notification.fireDate = firstDate
UIApplication.sharedApplication().scheduleLocalNotification(notification)
notifi = notifi + 1
}else {
print("local notifications limit has been reached")
}
}