VandyApps / vandyvans-ios

Vandy Vans Project for iOS
8 stars 3 forks source link

Reminders Should Self-Update #29

Open sethfri opened 10 years ago

sethfri commented 10 years ago

This is the current Reminder flow:

  1. A van has a prediction, e.g. 5 minutes away
  2. A user sets a reminder for when the van is 2 minutes away.
  3. The app counts down (prediction - 2) minutes and then alerts the user.

However, the van could have gotten slowed down (or even potentially have sped up), so before alerting the user, the app should make another network request to get the current prediction for the van. If it has slowed down, the app can reset the time and only ever alert the user when the van is actually 2 minutes away. If it has sped up, the app can relay this to the user as well with something like "It looks like the van is ahead of schedule! The van is 1 minute away from Branscomb."

rnc505 commented 10 years ago

How would you see this working? Like schedule a local notification that doesn't immediately alert the user, but causes the app to do a network request and the either immediately alerts (if it is 2 minutes or less) or waits (if more than 2 minutes).

So were you thinking something like a background app refresh/fetch (https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW24) or a background task (https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW28)?

I don't think background refresh is consistent, but background task is better. Whats your opinion, @sethfri ?

Proposed new reminder flow:

  1. A van has a prediction, e.g. 5 minutes away
  2. A user sets a reminder for when the van is 2 minutes away.
  3. Set a (global) NSTimer, single fire.
  4. If app goes to background, check if global NSTimer is valid. If so (i.e. reminder has been set), set up background refresh/background task.
  5. When the 2 minute reminder gets hit either via the NSTimer or the background task timer (I'll have to look into this), make a network request. If it is 2 minutes or less, create an immediate UILocalNotification. If it is more than 2 minutes, GOTO step 3.

This issue with testing something like this is that we need live data.

sethfri commented 10 years ago

@rnc505 How I originally anticipated the flow was this:

  1. A van has a prediction, e.g. 5 minutes away
  2. A user sets a reminder for when the van is 2 minutes away
  3. Set a UILocalNotification for (prediction - 2) minutes.
  4. In application:didReceiveLocalNotification:, make a network request. If it is 2 minutes or less, handle the UILocalNotification that has been passed in. If not, GOTO step 3.

I think this flow is better because we don't have to worry about any NSTimers, particularly global ones. Thoughts?

If we could also work to start making this generic (e.g. a method takes in a requestedReminderTime param or something instead of just hardcoding 2 everywhere, but then passing a hardcoded 2 into that method for now until we get more set up later), that would be really helpful for later. In the swipe branch, I'm currently working on the UI for Vandy Vans 2.0, which will include variable reminder times from #30.

Regarding your live data comment, the vans are running until 5 AM Saturday morning, so we still have a bit of time if you're able to get this done before then.

(Also, your background fetch and background task links above don't seem to be working for me - they both link to near the top of the same page)

rnc505 commented 10 years ago

@sethfri -- Maybe I don't fully understand how application:didReceiveLocalNotification: works. From what I've been reading, that delegate method only gets called if the app is in the background and the user clicks on the local notification -- this could be incorrect, but what I am fairly sure about is that the method gets called AFTER a local notification is handled, whereas we are looking for something that gets called BEFORE a local notification is handled.

Your workflow makes sense, but only if the application is in the foreground when the notification gets posted. Here's my suggested workflow that should handle both foreground and background cases:

  1. A van has a prediction, e.g. 5 minutes away
  2. A user sets a reminder for when the van is 2 minutes away
  3. Set a UILocalNotification for (prediction - 2) minutes.

4a. If user sends application to the background, deregister the/all UILocalNotification and cache them and create a background execution handler (see beginBackgroundTaskWithName:expirationHandler: in Application Delegate. This background execution handler will wait the designated time and then make a network request. If time <= 2, create and send immediate UILocalNotification, else back to step 3. If User returns to application, kill background execution handler and reregister UILocalNotifications. 4b. If user has application in the foreground, In application:didReceiveLocalNotification:, make a network request. If it is 2 minutes or less, handle the UILocalNotification that has been passed in. If not, GOTO step 3.

If the UILocalNotification fires (or is supposed to, see 4a) while in the background, the background execution handler will handle the network request to prevent the user from being notified with an OS alert for a possibly incorrect arrival notification. If it fires in the foreground, application:didReceiveLocalNotification: will take care of it.

Its the handling possibly incorrect notification times while the application is in the background that adds a level of complexity.