Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

Commit

Permalink
Deep Links and Shared Trips
Browse files Browse the repository at this point in the history
This feature wasn't so much driven by specific user request as it is driven to replace the hacky workarounds I've seen users use to accomplish the same thing.

Here are the key points of this commit:

1. Allows users to share the trip they are taking with another person via text message or any other form of communication vended through UIActivityViewController.
2. Trips are shared via URL. These URLs encode the ID of the region that their trips belong to, which means that they are globally unique. They also do not depend on individual OBA region servers, which means that the iOS app doesn't need region server information hardcoded into it.
3. People with OneBusAway for iOS are taken to the trip itself when they tap on one of these links.
4. People without OBA for iOS are taken first to http://onebusaway.co, and then redirected to the appropriate region server's web page for that trip.

-------

Fixes:

* Fixes #833 - 'Follow My Trip' Feature
* Fixes #840 - Implement Deep Linking
* Fixes #847 - Add option to delete individual recent stops

-------

Deep Links/Shared Trips:

* Deep link router class
* Create OBATripDeepLink model object
* Shared Trip infrastructure for model DAO and the user defaults-based persistence layer
* Display shared trips on the Recent tab
* Delete shared trips older than 24 hours
* Make it possible to render the ArrivalAndDeparture controller from a Trip Deep Link object
* Start overhauling OBANavigationTarget
* Wire up navigation target stuff for OBARecentStopsViewController
* Shoehorn in a way to launch differently in response to deep links.
* Unify navigation target, deep link, and 3D Touch quick action navigation systems

Miscellaneous:

* Move -escapePathVariable into OBAURLHelpers
* Fix credits - turns out that I didn't end up adding the credits.html file back to the project when I did the big project reorg last month. Oops.

Cell Swiping:

* Add third party library YMSwipeTableViewCell to allow us to display icons on swiped cells (only on the stop view controller for now!)
* Improved swipe menu for departure rows on the stops controller

Icons:

* New bookmark icons
* Massively improve tab bar icons
* Update launch storyboard - remove text and ensure that the icons are the correct, new ones
* Add full sized icons from Noun Project to the Resources folder
  • Loading branch information
aaronbrethorst committed Nov 4, 2016
1 parent 924cfc7 commit 899d29f
Show file tree
Hide file tree
Showing 97 changed files with 2,714 additions and 470 deletions.
17 changes: 17 additions & 0 deletions OBAKit/Categories/NSURLQueryItem+OBAAdditions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// NSURLQueryItem+OBAAdditions.h
// OBAKit
//
// Created by Aaron Brethorst on 10/30/16.
// Copyright © 2016 OneBusAway. All rights reserved.
//

@import Foundation;

NS_ASSUME_NONNULL_BEGIN

@interface NSURLQueryItem (OBAAdditions)
+ (NSDictionary*)oba_dictionaryFromQueryItems:(nullable NSArray<NSURLQueryItem*>*)queryItems;
@end

NS_ASSUME_NONNULL_END
29 changes: 29 additions & 0 deletions OBAKit/Categories/NSURLQueryItem+OBAAdditions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// NSURLQueryItem+OBAAdditions.m
// OBAKit
//
// Created by Aaron Brethorst on 10/30/16.
// Copyright © 2016 OneBusAway. All rights reserved.
//

#import <OBAKit/NSURLQueryItem+OBAAdditions.h>

@implementation NSURLQueryItem (OBAAdditions)

+ (NSDictionary*)oba_dictionaryFromQueryItems:(NSArray<NSURLQueryItem*>*)queryItems {
if (queryItems.count == 0) {
return @{};
}

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];

for (NSURLQueryItem *item in queryItems) {
if (item.value) {
dictionary[item.name] = item.value;
}
}

return [NSDictionary dictionaryWithDictionary:dictionary];
}

@end
11 changes: 3 additions & 8 deletions OBAKit/Helpers/OBACommonV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@
@import Foundation;

typedef NS_ENUM(NSInteger, OBANavigationTargetType) {
OBANavigationTargetTypeRoot=0,
OBANavigationTargetTypeSearch,
OBANavigationTargetTypeUndefined=0,
OBANavigationTargetTypeMap,
OBANavigationTargetTypeSearchResults,
OBANavigationTargetTypeBookmarks,
OBANavigationTargetTypeRecentStops,
OBANavigationTargetTypeStop,
OBANavigationTargetTypeEditBookmark,
OBANavigationTargetTypeEditStopPreferences,
OBANavigationTargetTypeSettings,
OBANavigationTargetTypeBookmarks,
OBANavigationTargetTypeContactUs,
OBANavigationTargetTypeAgencies,
};
22 changes: 22 additions & 0 deletions OBAKit/Helpers/OBADeepLinkRouter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// OBADeepLinkRouter.h
// OBAKit
//
// Created by Aaron Brethorst on 10/28/16.
// Copyright © 2016 OneBusAway. All rights reserved.
//

@import Foundation;

NS_ASSUME_NONNULL_BEGIN

typedef void(^OBADeepLinkAction)(NSArray<NSString*> *matchGroupResults, NSURLComponents *URLComponents);

@interface OBADeepLinkRouter : NSObject

- (void)routePattern:(NSString*)pattern toAction:(OBADeepLinkAction)action;
- (BOOL)performActionForURL:(NSURL*)URL;

@end

NS_ASSUME_NONNULL_END
56 changes: 56 additions & 0 deletions OBAKit/Helpers/OBADeepLinkRouter.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// OBADeepLinkRouter.m
// OBAKit
//
// Created by Aaron Brethorst on 10/28/16.
// Copyright © 2016 OneBusAway. All rights reserved.
//

#import "OBADeepLinkRouter.h"

@interface OBADeepLinkRouter ()
@property(nonatomic,strong) NSMutableDictionary *routes;
@end

@implementation OBADeepLinkRouter

- (instancetype)init {
self = [super init];
if (self) {
_routes = [[NSMutableDictionary alloc] init];
}
return self;
}

- (void)routePattern:(NSString*)pattern toAction:(OBADeepLinkAction)action {
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil];
self.routes[regex] = [action copy];
}

- (BOOL)performActionForURL:(NSURL*)URL {
NSArray *keys = [self.routes.allKeys copy];
NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
NSString *path = URLComponents.path;

for (NSRegularExpression *regex in keys) {
NSTextCheckingResult *result = [regex firstMatchInString:path options:(NSMatchingOptions)0 range:NSMakeRange(0, path.length)];

if (result) {
NSMutableArray *matchValues = [NSMutableArray new];

for (NSUInteger i=1; i<result.numberOfRanges; i++) {
NSString *value = [path substringWithRange:[result rangeAtIndex:i]];
[matchValues addObject:value];
}

OBADeepLinkAction action = self.routes[regex];
action([matchValues copy], URLComponents);

return YES;
}
}

return NO;
}

@end
2 changes: 2 additions & 0 deletions OBAKit/Helpers/OBALogging.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ NS_ASSUME_NONNULL_BEGIN

extern const DDLogLevel ddLogLevel;

#define OBALogFunction() DDLogInfo(@"%s", __PRETTY_FUNCTION__)

@interface OBALogging : NSObject
@property(nonatomic,strong,readonly) OBAConsoleLogger *consoleLogger;
- (NSArray<NSData*>*)logFileData;
Expand Down
1 change: 1 addition & 0 deletions OBAKit/Helpers/OBAURLHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface OBAURLHelpers : NSObject
+ (NSURL*)normalizeURLPath:(NSString*)path relativeToBaseURL:(NSString*)baseURLString parameters:(NSDictionary* _Nullable)params;
+ (NSString*)escapePathVariable:(NSString*)pathVariable;
@end

NS_ASSUME_NONNULL_END
8 changes: 8 additions & 0 deletions OBAKit/Helpers/OBAURLHelpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ + (NSURL*)normalizeURLPath:(NSString*)path relativeToBaseURL:(NSString*)baseURLS
return components.URL;
}

+ (NSString*)escapePathVariable:(NSString*)pathVariable {
NSString *escaped = [pathVariable stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
// Apparently -stringByAddingPercentEncodingWithAllowedCharacters: won't remove
// '/' characters from paths, so we get to do that manually here. Boo.
// https://github.com/OneBusAway/onebusaway-iphone/issues/817
return [escaped stringByReplacingOccurrencesOfString:@"/" withString:@"%2F"];
}

@end
2 changes: 1 addition & 1 deletion OBAKit/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundleShortVersionString</key>
<string>2.6.5</string>
<key>CFBundleVersion</key>
<string>20161028.11</string>
<string>20161104.13</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
Expand Down
22 changes: 19 additions & 3 deletions OBAKit/Models/dao/OBAModelDAO.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import <OBAKit/OBAServiceAlertsModel.h>
#import <OBAKit/OBARegionV2.h>
#import <OBAKit/OBAModelPersistenceLayer.h>
#import <OBAKit/OBATripDeepLink.h>

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -41,34 +42,41 @@ extern NSString * const OBARegionDidUpdateNotification;

- (instancetype)initWithModelPersistenceLayer:(id<OBAModelPersistenceLayer>)persistenceLayer;

// Bookmarks

- (NSArray<OBABookmarkV2*>*)bookmarksMatchingPredicate:(NSPredicate*)predicate;
- (nullable OBABookmarkV2*)bookmarkForArrivalAndDeparture:(OBAArrivalAndDepartureV2*)arrival;
- (void)saveBookmark:(OBABookmarkV2*)bookmark;
- (void)moveBookmark:(NSUInteger)startIndex to:(NSUInteger)endIndex;
- (void)removeBookmark:(OBABookmarkV2*)bookmark;

- (nullable OBABookmarkV2*)bookmarkAtIndex:(NSUInteger)index inGroup:(nullable OBABookmarkGroup*)group;
- (void)moveBookmark:(OBABookmarkV2*)bookmark toIndex:(NSUInteger)index inGroup:(nullable OBABookmarkGroup*)group;
- (void)moveBookmark:(OBABookmarkV2*)bookmark toGroup:(nullable OBABookmarkGroup*)group;
- (void)moveBookmark:(NSUInteger)startIndex to:(NSUInteger)endIndex inGroup:(OBABookmarkGroup*)group;

// Bookmark Groups

- (void)moveBookmarkGroup:(OBABookmarkGroup*)bookmarkGroup toIndex:(NSUInteger)index;
- (void)saveBookmarkGroup:(OBABookmarkGroup *)bookmarkGroup;
- (void)removeBookmarkGroup:(OBABookmarkGroup*)bookmarkGroup;
- (void)persistGroups;

// Stop Preferences

- (OBAStopPreferencesV2*)stopPreferencesForStopWithId:(NSString*)stopId;
- (void)setStopPreferences:(OBAStopPreferencesV2*)preferences forStopWithId:(NSString*)stopId;

- (BOOL) isVisitedSituationWithId:(NSString*)situationId;
- (void) setVisited:(BOOL)visited forSituationWithId:(NSString*)situationId;
// Service Alerts

- (BOOL)isVisitedSituationWithId:(NSString*)situationId;
- (void)setVisited:(BOOL)visited forSituationWithId:(NSString*)situationId;
- (OBAServiceAlertsModel*) getServiceAlertsModelForSituations:(NSArray*)situations;

// Recent Stops

- (void)clearMostRecentStops;
- (void)viewedArrivalsAndDeparturesForStop:(OBAStopV2*)stop;
- (void)removeRecentStop:(OBAStopAccessEventV2*)recentStop;

// Regions

Expand All @@ -82,6 +90,14 @@ extern NSString * const OBARegionDidUpdateNotification;
@property(nonatomic,assign) BOOL shareLocationPII;
@property(nonatomic,assign) BOOL shareLogsPII;

// Shared Trips

@property(nonatomic,copy,readonly) NSArray<OBATripDeepLink*> *sharedTrips;
- (void)addSharedTrip:(OBATripDeepLink*)sharedTrip;
- (void)removeSharedTrip:(OBATripDeepLink*)sharedTrip;
- (void)clearSharedTrips;
- (void)clearSharedTripsOlderThan24Hours;

@end

NS_ASSUME_NONNULL_END
46 changes: 45 additions & 1 deletion OBAKit/Models/dao/OBAModelDAO.m
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ - (void) setHideFutureLocationWarnings:(BOOL)hideFutureLocationWarnings {
[_preferencesDao setHideFutureLocationWarnings:hideFutureLocationWarnings];
}

#pragma mark - Stop Viewing
#pragma mark - Recent Stops

- (void)clearMostRecentStops {
[_mostRecentStops removeAllObjects];
Expand Down Expand Up @@ -458,6 +458,14 @@ - (void)viewedArrivalsAndDeparturesForStop:(OBAStopV2*)stop {
[self addStopAccessEvent:event];
}

- (void)removeRecentStop:(OBAStopAccessEventV2*)recentStop {
[_mostRecentStops removeObject:recentStop];
[_preferencesDao writeMostRecentStops:_mostRecentStops];
[[NSNotificationCenter defaultCenter] postNotificationName:OBAMostRecentStopsChangedNotification object:nil];
}

#pragma mark - Service Alerts

- (BOOL)isVisitedSituationWithId:(NSString*)situationId {
return [self.visitedSituationIds containsObject:situationId];
}
Expand Down Expand Up @@ -535,5 +543,41 @@ - (BOOL)shareLogsPII {
return [_preferencesDao shareLogsPII];
}

#pragma mark - Shared Trips

- (NSArray<OBATripDeepLink*>*)sharedTrips {
return [[_preferencesDao sharedTrips].allObjects sortedArrayUsingSelector:@selector(compare:)];
}

- (void)addSharedTrip:(OBATripDeepLink*)sharedTrip {
[_preferencesDao addSharedTrip:sharedTrip];
}

- (void)removeSharedTrip:(OBATripDeepLink*)sharedTrip {
[_preferencesDao removeSharedTrip:sharedTrip];
}

- (void)clearSharedTrips {
NSArray<OBATripDeepLink*> *sharedTrips = self.sharedTrips;
for (OBATripDeepLink *link in sharedTrips) {
[self removeSharedTrip:link];
}
}

- (void)clearSharedTripsOlderThan24Hours {
NSMutableArray *toPurge = [NSMutableArray new];
NSDate *purgeDate = [NSDate dateWithTimeIntervalSinceNow:-86400.0]; // 86,400 seconds in a day.

for (OBATripDeepLink *link in self.sharedTrips) {
if ([link.createdAt timeIntervalSinceDate:purgeDate] < 0) {
[toPurge addObject:link];
}
}

for (OBATripDeepLink *link in toPurge) {
[self removeSharedTrip:link];
}
}

@end

Loading

0 comments on commit 899d29f

Please sign in to comment.