@@ -34,6 +34,8 @@ @interface GLManager()
3434@property (strong , nonatomic ) LOLDatabase *db;
3535@property (strong , nonatomic ) FMDatabase *tripdb;
3636
37+ @property (strong , nonatomic ) NSDate *lastScheduledNotificationDate;
38+
3739@end
3840
3941@implementation GLManager
@@ -722,6 +724,8 @@ - (void)enableTracking {
722724 if (self.locationManager .location ) {
723725 self.lastLocation = self.locationManager .location ;
724726 }
727+
728+ [self scheduleLocalNotification ];
725729}
726730
727731- (void )disableTracking {
@@ -735,6 +739,7 @@ - (void)disableTracking {
735739 [self .motionActivityManager stopActivityUpdates ];
736740 self.lastMotion = nil ;
737741 }
742+ [self cancelLocalNotification ];
738743}
739744
740745- (void )sendingStarted {
@@ -778,6 +783,58 @@ - (void)sendQueueIfNotInProgress {
778783 self.lastSentDate = NSDate .date ;
779784}
780785
786+ #pragma mark - Scheduled local notifications
787+
788+ - (void )scheduleLocalNotification {
789+ // Schedule a local notification for 10 minutes into the future to remind the user to launch the app.
790+ // We'll cancel the notification when we get an update from the system, so this should only
791+ // run if the app is shut down for some reason.
792+
793+ int scheduleRateLimit = 60 ;
794+ int reminderIntervalSeconds = 600 ;
795+
796+ // Only do this at most once a minute so we don't hammer the system with scheduled notification requests
797+ NSDate *lastScheduled = self.lastScheduledNotificationDate ;
798+ if (lastScheduled != nil && [lastScheduled timeIntervalSinceNow ] > -1 * scheduleRateLimit) {
799+ return ;
800+ }
801+
802+ [self cancelLocalNotification ];
803+
804+ UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc ] init ];
805+ content.title = [NSString localizedUserNotificationStringForKey: @" Overland" arguments: nil ];
806+ content.body = [NSString localizedUserNotificationStringForKey: @" Location updates were stopped. Launch the app to resume."
807+ arguments: nil ];
808+ content.sound = [UNNotificationSound defaultSound ];
809+
810+ UNTimeIntervalNotificationTrigger * trigger = [UNTimeIntervalNotificationTrigger
811+ triggerWithTimeInterval: reminderIntervalSeconds repeats: NO ];
812+ UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier: @" reminder"
813+ content: content trigger: trigger];
814+
815+ UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter ];
816+ [center addNotificationRequest: request withCompletionHandler: ^(NSError * _Nullable error) {
817+ self.lastScheduledNotificationDate = NSDate .now ;
818+ }];
819+ }
820+
821+ - (void )cancelLocalNotification {
822+ UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter ];
823+ [center removePendingNotificationRequestsWithIdentifiers: @[@" reminder" ]];
824+ }
825+
826+ - (NSDate *)lastScheduledNotificationDate {
827+ if ([self defaultsKeyExists: GLLastScheduledNotificationDateDefaultsName]) {
828+ return (NSDate *)[[NSUserDefaults standardUserDefaults ] objectForKey: GLLastScheduledNotificationDateDefaultsName];
829+ } else {
830+ return nil ;
831+ }
832+ }
833+ - (void )setLastScheduledNotificationDate : (NSDate *)date {
834+ [[NSUserDefaults standardUserDefaults ] setObject: date forKey: GLLastScheduledNotificationDateDefaultsName];
835+ }
836+
837+
781838#pragma mark - Trips
782839
783840+ (NSArray *)GLTripModes {
@@ -1668,6 +1725,8 @@ - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray
16681725 }
16691726
16701727 [self sendQueueIfTimeElapsed ];
1728+
1729+ [self scheduleLocalNotification ];
16711730}
16721731
16731732- (void )addMetadataToUpdate : (NSDictionary *) update {
0 commit comments