Skip to content

Commit

Permalink
Add UILocalNotification reminders for favorited events
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisballinger committed Aug 13, 2014
1 parent dc15da1 commit 42505a1
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 30 deletions.
3 changes: 2 additions & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ pod 'MCSwipeTableViewCell', '~> 2.1'
pod 'DAKeyboardControl', '~> 2.4'
pod 'BButton', '~> 4.0'
pod 'VTAcknowledgementsViewController', '~> 0.11'
pod 'TTTAttributedLabel', '~> 1.10'
pod 'TTTAttributedLabel', '~> 1.10'
pod 'UIAlertView-Blocks', '~> 1.0'
3 changes: 3 additions & 0 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ PODS:
- PureLayout (1.0.1)
- SMCalloutView (2.0)
- TTTAttributedLabel (1.10.1)
- UIAlertView-Blocks (1.0)
- VTAcknowledgementsViewController (0.11)
- YapDatabase (2.5):
- YapDatabase/standard
Expand All @@ -48,6 +49,7 @@ DEPENDENCIES:
- MCSwipeTableViewCell (~> 2.1)
- PureLayout (~> 1.0)
- TTTAttributedLabel (~> 1.10)
- UIAlertView-Blocks (~> 1.0)
- VTAcknowledgementsViewController (~> 0.11)
- YapDatabase (from `https://github.com/chrisballinger/YapDatabase.git`, commit `a3778fb0a5917426e75b17a2776f703e34df403f`)

Expand All @@ -71,6 +73,7 @@ SPEC CHECKSUMS:
PureLayout: 972964b21dbcbc5cc36785aed16aba03176f057d
SMCalloutView: c1906604d47c058400ade5c9d52ab98aa77b7e76
TTTAttributedLabel: 94bb04f1e005616002dd2cee0262a0082e533627
UIAlertView-Blocks: f3271e84372beb97aea115cd1fb26ae66457f12f
VTAcknowledgementsViewController: 6e71652adbe73c68f0a278a73ac9ca1e1fc00b90
YapDatabase: 38ee5e842ed1370f0d258e25b23bd64f6e3c1a67

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Fortunately, you can still run and test the app with the previous year's data.

* load `image_url` for art when internet is available
* Open in Safari pop up when clicking links
* Add UILocationNotification on favoriting event
* Onboarding
* Show data from previous years
* Optimizations (only load 1 day of events at a time)
Expand Down
8 changes: 8 additions & 0 deletions iBurn/BRCAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@

#import <UIKit/UIKit.h>
#import "HockeySDK.h"
#import "BRCMapViewController.h"
#import "BRCEventsTableViewController.h"


@interface BRCAppDelegate : UIResponder <UIApplicationDelegate, BITHockeyManagerDelegate, UITabBarControllerDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) UITabBarController *tabBarController;

@property (nonatomic, strong) BRCMapViewController *mapViewController;
@property (nonatomic, strong) BRCFilteredTableViewController *artViewController;
@property (nonatomic, strong) BRCFilteredTableViewController *campsViewController;
@property (nonatomic, strong) BRCEventsTableViewController *eventsViewController;

- (void)showTabBarAnimated:(BOOL)animated;

@end
56 changes: 40 additions & 16 deletions iBurn/BRCAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#import "BRCEmbargoPasscodeViewController.h"
#import "BRCEmbargo.h"
#import "NSUserDefaults+iBurn.h"
#import "BRCEventObject.h"
#import "UIAlertView+Blocks.h"
#import "BRCFilteredTableViewController_Private.h"
#import "BRCDetailViewController.h"

@implementation BRCAppDelegate

Expand Down Expand Up @@ -56,6 +60,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
self.window.rootViewController = [[BRCEmbargoPasscodeViewController alloc] init];
}

UILocalNotification *launchNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (launchNotification) {
[self application:application didReceiveLocalNotification:launchNotification];
}
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
Expand All @@ -67,12 +75,28 @@ - (void) application:(UIApplication *)application didReceiveLocalNotification:(U
[[NSUserDefaults standardUserDefaults] scheduleLocalNotificationForGateUnlock:nil];
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:notification.alertBody delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
RIButtonItem *cancelItem = [RIButtonItem itemWithLabel:@"Dismiss"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:notification.alertBody cancelButtonItem:cancelItem otherButtonItems:nil];
if (notification.alertAction.length > 0) {
[alert addButtonWithTitle:notification.alertAction];
} else {
[alert addButtonWithTitle:@"OK"];
NSString *eventKey = [BRCEventObject localNotificationUserInfoKey];
NSString *eventUniqueID = [notification.userInfo objectForKey:eventKey];
dispatch_block_t actionBlock = nil;
if (eventUniqueID) {
actionBlock = ^{
[self.tabBarController setSelectedViewController:self.eventsViewController.navigationController];
__block BRCEventObject *event = nil;
[self.eventsViewController.databaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
event = [transaction objectForKey:eventUniqueID inCollection:[BRCEventObject collection]];
} completionBlock:^{
if (event) {
BRCDetailViewController *detailVC = [[BRCDetailViewController alloc] initWithDataObject:event];
[self.eventsViewController.navigationController pushViewController:detailVC animated:YES];
}
}];
};
}
RIButtonItem *actionItem = [RIButtonItem itemWithLabel:notification.alertAction action:actionBlock];
[alert addButtonItem:actionItem];
}
[alert show];
}
Expand Down Expand Up @@ -118,23 +142,23 @@ - (void)showTabBarAnimated:(BOOL)animated{

- (void)setupDefaultTabBarController
{
BRCMapViewController *mapViewController = [[BRCMapViewController alloc] init];
UINavigationController *mapNavController = [[UINavigationController alloc] initWithRootViewController:mapViewController];
self.mapViewController = [[BRCMapViewController alloc] init];
UINavigationController *mapNavController = [[UINavigationController alloc] initWithRootViewController:self.mapViewController];
mapNavController.tabBarItem.image = [UIImage imageNamed:@"BRCMapIcon"];

BRCFilteredTableViewController *artTableVC = [[BRCFilteredTableViewController alloc] initWithViewClass:[BRCArtObject class]];
artTableVC.title = @"Art";
UINavigationController *artNavController = [[UINavigationController alloc] initWithRootViewController:artTableVC];
self.artViewController = [[BRCFilteredTableViewController alloc] initWithViewClass:[BRCArtObject class]];
self.artViewController.title = @"Art";
UINavigationController *artNavController = [[UINavigationController alloc] initWithRootViewController:self.artViewController];
artNavController.tabBarItem.image = [UIImage imageNamed:@"BRCArtIcon"];

BRCFilteredTableViewController *campTableVC = [[BRCFilteredTableViewController alloc] initWithViewClass:[BRCCampObject class]];
campTableVC.title = @"Camps";
UINavigationController *campNavController = [[UINavigationController alloc] initWithRootViewController:campTableVC];
self.campsViewController = [[BRCFilteredTableViewController alloc] initWithViewClass:[BRCCampObject class]];
self.campsViewController.title = @"Camps";
UINavigationController *campNavController = [[UINavigationController alloc] initWithRootViewController:self.campsViewController];
campNavController.tabBarItem.image = [UIImage imageNamed:@"BRCCampIcon"];

BRCEventsTableViewController *eventsTableVC = [[BRCEventsTableViewController alloc] initWithViewClass:[BRCEventObject class]];
eventsTableVC.title = @"Events";
UINavigationController *eventsNavController = [[UINavigationController alloc] initWithRootViewController:eventsTableVC];
self.eventsViewController = [[BRCEventsTableViewController alloc] initWithViewClass:[BRCEventObject class]];
self.eventsViewController.title = @"Events";
UINavigationController *eventsNavController = [[UINavigationController alloc] initWithRootViewController:self.eventsViewController];
eventsNavController.tabBarItem.image = [UIImage imageNamed:@"BRCEventIcon"];

self.tabBarController = [[UITabBarController alloc] init];
Expand Down
3 changes: 2 additions & 1 deletion iBurn/BRCDataObjectTableViewCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
@property (strong, nonatomic) IBOutlet UILabel *subtitleLabel;
@property (nonatomic, strong) BRCDataObject *dataObject;

- (void) setStyleFromDataObject:(BRCDataObject*)dataObject;

+ (NSString*) cellIdentifier;
+ (CGFloat) cellHeight;
Expand Down
5 changes: 1 addition & 4 deletions iBurn/BRCDataObjectTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@

@implementation BRCDataObjectTableViewCell

- (void) setDataObject:(BRCDataObject*)dataObject {
_dataObject = dataObject;

- (void) setStyleFromDataObject:(BRCDataObject*)dataObject {
self.titleLabel.text = dataObject.title;

[self setTitleLabelBold:dataObject.isFavorite];
}

Expand Down
9 changes: 9 additions & 0 deletions iBurn/BRCDetailViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ - (void)didTapFavorite:(id)sender
tempObject = [tempObject copy];
tempObject.isFavorite = !tempObject.isFavorite;
[transaction setObject:tempObject forKey:tempObject.uniqueID inCollection:[[tempObject class] collection]];
if ([tempObject isKindOfClass:[BRCEventObject class]]) {
BRCEventObject *event = (BRCEventObject*)tempObject;
if (event.isFavorite) {
[BRCEventObject scheduleNotificationForEvent:event transaction:transaction];
} else {
[BRCEventObject cancelScheduledNotificationForEvent:event transaction:transaction];
}

}
}
} completionBlock:^{
self.dataObject = tempObject;
Expand Down
9 changes: 9 additions & 0 deletions iBurn/BRCEventObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "BRCDataObject.h"
#import "YapDatabaseTransaction.h"

typedef NS_ENUM(NSUInteger, BRCEventType) {
BRCEventTypeUnknown,
Expand Down Expand Up @@ -96,4 +97,12 @@ typedef NS_ENUM(NSUInteger, BRCEventType) {
/** convert BRCEventType to display string */
+ (NSString *)stringForEventType:(BRCEventType)type;


/** eventObject must be isFavorite first */
+ (void) scheduleNotificationForEvent:(BRCEventObject*)eventObject transaction:(YapDatabaseReadWriteTransaction*)transaction;
/** eventObject must not be favorite */
+ (void) cancelScheduledNotificationForEvent:(BRCEventObject*)eventObject transaction:(YapDatabaseReadWriteTransaction*)transaction;
/** userInfo contains the event's uniqueID under this key */
+ (NSString*) localNotificationUserInfoKey;

@end
43 changes: 43 additions & 0 deletions iBurn/BRCEventObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#import "MTLValueTransformer.h"
#import "BRCEventObject_Private.h"
#import "UIColor+iBurn.h"
#import "NSDateFormatter+iBurn.h"
#import "BRCDatabaseManager.h"

NSString * const kBRCStartDateKey = @"kBRCStartDateKey";
NSString * const kBRCEndDateKey = @"kBRCEndDateKey";
Expand Down Expand Up @@ -229,4 +231,45 @@ + (NSString *)stringForEventType:(BRCEventType)type
}
}

+ (void) scheduleNotificationForEvent:(BRCEventObject*)eventObject transaction:(YapDatabaseReadWriteTransaction*)transaction {
NSParameterAssert(eventObject.isFavorite);
if (!eventObject.scheduledNotification) {
// remind us 30 minutes before
NSDate *reminderDate = [eventObject.startDate dateByAddingTimeInterval:-30 * 60];
//NSDate *testingReminderDate = [[NSDate date] dateByAddingTimeInterval:10];
NSString *startTimeString = [[NSDateFormatter brc_timeOnlyDateFormatter] stringFromDate:eventObject.startDate];
NSString *reminderTitle = [NSString stringWithFormat:@"%@ - %@", startTimeString, eventObject.title];
UILocalNotification *eventNotification = [[UILocalNotification alloc] init];
eventNotification.fireDate = reminderDate;
eventNotification.alertBody = reminderTitle;
eventNotification.soundName = UILocalNotificationDefaultSoundName;
eventNotification.alertAction = @"View Event";
eventNotification.applicationIconBadgeNumber = 1;
NSString *key = [self localNotificationUserInfoKey];
eventNotification.userInfo = @{key: eventObject.uniqueID};
eventObject.scheduledNotification = eventNotification;
[transaction setObject:eventObject forKey:eventObject.uniqueID inCollection:[BRCEventObject collection]];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] scheduleLocalNotification:eventNotification];
});
}
}

+ (NSString*) localNotificationUserInfoKey {
NSString *key = [NSString stringWithFormat:@"%@-%@", NSStringFromClass([self class]), NSStringFromSelector(@selector(uniqueID))];
return key;
}

+ (void) cancelScheduledNotificationForEvent:(BRCEventObject*)eventObject transaction:(YapDatabaseReadWriteTransaction*)transaction {
NSParameterAssert(!eventObject.isFavorite);
if (eventObject.scheduledNotification) {
UILocalNotification *notificationToCancel = eventObject.scheduledNotification;
eventObject.scheduledNotification = nil;
[transaction setObject:eventObject forKey:eventObject.uniqueID inCollection:[BRCEventObject collection]];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] cancelLocalNotification:notificationToCancel];
});
}
}

@end
4 changes: 2 additions & 2 deletions iBurn/BRCEventObjectTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

@implementation BRCEventObjectTableViewCell

- (void) setDataObject:(BRCDataObject*)dataObject {
[super setDataObject:dataObject];
- (void) setStyleFromDataObject:(BRCDataObject*)dataObject {
[super setStyleFromDataObject:dataObject];
BRCEventObject *eventObject = (BRCEventObject*)dataObject;
if (eventObject.isAllDay) {
self.eventTimeLabel.text = @"All Day";
Expand Down
18 changes: 14 additions & 4 deletions iBurn/BRCFilteredTableViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
{
BRCDataObjectTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[[self cellClass] cellIdentifier] forIndexPath:indexPath];
__block BRCDataObject *dataObject = [self dataObjectForIndexPath:indexPath tableView:tableView];
cell.dataObject = dataObject;
[cell setStyleFromDataObject:dataObject];
[cell updateDistanceLabelFromLocation:self.locationManager.location toLocation:dataObject.location];
// Adding gestures per state basis.
UIImageView *viewState = [self imageViewForFavoriteStatus:dataObject.isFavorite];
Expand All @@ -465,8 +465,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
dataObject = [[transaction objectForKey:dataObject.uniqueID inCollection:[[dataObject class] collection]] copy];
}];
dataObject.isFavorite = !dataObject.isFavorite;
dataCell.dataObject = dataObject;
[dataCell setStyleFromDataObject:dataObject];
[[BRCDatabaseManager sharedInstance].readWriteDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
if ([dataObject isKindOfClass:[BRCEventObject class]]) {
BRCEventObject *event = (BRCEventObject*)dataObject;
if (event.isFavorite) {
[BRCEventObject scheduleNotificationForEvent:event transaction:transaction];
} else {
[BRCEventObject cancelScheduledNotificationForEvent:event transaction:transaction];
}
}
[transaction setObject:dataObject forKey:dataObject.uniqueID inCollection:[[dataObject class] collection]];
} completionBlock:nil];
}];
Expand All @@ -475,14 +483,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}

- (void)swipeTableViewCell:(BRCDataObjectTableViewCell *)cell didSwipeWithPercentage:(CGFloat)percentage {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
__block BRCDataObject *dataObject = [self dataObjectForIndexPath:indexPath tableView:self.tableView];
// We want to switch states to give a hint of the future value
// is there a way to optimize this further?
if (percentage >= cell.firstTrigger) {
BOOL inverseFavorite = !cell.dataObject.isFavorite;
BOOL inverseFavorite = !dataObject.isFavorite;
cell.view1 = [self imageViewForFavoriteStatus:inverseFavorite];
[cell setTitleLabelBold:inverseFavorite];
} else if (percentage < cell.firstTrigger) {
BOOL isFavorite = cell.dataObject.isFavorite;
BOOL isFavorite = dataObject.isFavorite;
cell.view1 = [self imageViewForFavoriteStatus:isFavorite];
[cell setTitleLabelBold:isFavorite];
}
Expand Down
2 changes: 1 addition & 1 deletion iBurn/BRCMapViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
__block BRCDataObject *dataObject = [self dataObjectForIndexPath:indexPath tableView:tableView];
Class cellClass = [self cellClassForDataObjectClass:[dataObject class]];
BRCDataObjectTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[cellClass cellIdentifier] forIndexPath:indexPath];
cell.dataObject = dataObject;
[cell setStyleFromDataObject:dataObject];
[cell updateDistanceLabelFromLocation:self.locationManager.location toLocation:dataObject.location];
return cell;
}
Expand Down

0 comments on commit 42505a1

Please sign in to comment.