diff --git a/TalkinToTheNet/.DS_Store b/TalkinToTheNet/.DS_Store new file mode 100644 index 0000000..20a0667 Binary files /dev/null and b/TalkinToTheNet/.DS_Store differ diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index ee35a70..c21bcc6 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -13,6 +13,10 @@ 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD521BAF859400A92AD2 /* Main.storyboard */; }; 8D7DCD561BAF859400A92AD2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */; }; 8D7DCD591BAF859400A92AD2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */; }; + D9DEF2D11BB607E10085F47E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D9DEF2D01BB607E10085F47E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; + D9DEF2D41BB608E00085F47E /* PlaceResult.m in Sources */ = {isa = PBXBuildFile; fileRef = D9DEF2D31BB608E00085F47E /* PlaceResult.m */; settings = {ASSET_TAGS = (); }; }; + D9DEF2D71BB61AEB0085F47E /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D9DEF2D61BB61AEB0085F47E /* DetailViewController.m */; settings = {ASSET_TAGS = (); }; }; + D9DEF2E01BB631C50085F47E /* MikeInstagramPost.m in Sources */ = {isa = PBXBuildFile; fileRef = D9DEF2DF1BB631C50085F47E /* MikeInstagramPost.m */; settings = {ASSET_TAGS = (); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -26,6 +30,14 @@ 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 8D7DCD581BAF859400A92AD2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 8D7DCD5A1BAF859400A92AD2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D9DEF2CF1BB607E10085F47E /* APIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIManager.h; sourceTree = ""; }; + D9DEF2D01BB607E10085F47E /* APIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APIManager.m; sourceTree = ""; }; + D9DEF2D21BB608E00085F47E /* PlaceResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlaceResult.h; sourceTree = ""; }; + D9DEF2D31BB608E00085F47E /* PlaceResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlaceResult.m; sourceTree = ""; }; + D9DEF2D51BB61AEB0085F47E /* DetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; + D9DEF2D61BB61AEB0085F47E /* DetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; + D9DEF2DE1BB631C50085F47E /* MikeInstagramPost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MikeInstagramPost.h; sourceTree = ""; }; + D9DEF2DF1BB631C50085F47E /* MikeInstagramPost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MikeInstagramPost.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,6 +74,14 @@ 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */, 8D7DCD4F1BAF859400A92AD2 /* ViewController.h */, 8D7DCD501BAF859400A92AD2 /* ViewController.m */, + D9DEF2CF1BB607E10085F47E /* APIManager.h */, + D9DEF2D01BB607E10085F47E /* APIManager.m */, + D9DEF2D21BB608E00085F47E /* PlaceResult.h */, + D9DEF2D31BB608E00085F47E /* PlaceResult.m */, + D9DEF2D51BB61AEB0085F47E /* DetailViewController.h */, + D9DEF2D61BB61AEB0085F47E /* DetailViewController.m */, + D9DEF2DE1BB631C50085F47E /* MikeInstagramPost.h */, + D9DEF2DF1BB631C50085F47E /* MikeInstagramPost.m */, 8D7DCD521BAF859400A92AD2 /* Main.storyboard */, 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */, 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */, @@ -149,9 +169,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D9DEF2D11BB607E10085F47E /* APIManager.m in Sources */, 8D7DCD511BAF859400A92AD2 /* ViewController.m in Sources */, + D9DEF2E01BB631C50085F47E /* MikeInstagramPost.m in Sources */, + D9DEF2D41BB608E00085F47E /* PlaceResult.m in Sources */, 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */, 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, + D9DEF2D71BB61AEB0085F47E /* DetailViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -300,6 +324,7 @@ 8D7DCD5F1BAF859400A92AD2 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.h b/TalkinToTheNet/TalkinToTheNet/APIManager.h new file mode 100644 index 0000000..553372f --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.h @@ -0,0 +1,17 @@ +// +// APIManager.h +// LearnAPI +// +// Created by Xiulan Shi on 9/20/15. +// Copyright © 2015 Xiulan Shi. All rights reserved. +// + +#import + +@interface APIManager : NSObject + ++ (void) GETRequestWithURL:(NSURL *)URL + completionHandler:(void(^)(NSData *data, NSURLResponse *response, NSError *error)) +completionBlock; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.m b/TalkinToTheNet/TalkinToTheNet/APIManager.m new file mode 100644 index 0000000..af4b145 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.m @@ -0,0 +1,29 @@ +// +// APIManager.m +// LearnAPI +// +// Created by Xiulan Shi on 9/20/15. +// Copyright © 2015 Xiulan Shi. All rights reserved. +// + +#import "APIManager.h" + +@implementation APIManager + ++ (void) GETRequestWithURL:(NSURL *)URL + completionHandler:(void(^)(NSData *data, NSURLResponse *response, NSError *error)) +completionBlock { + + NSURLSession *session = [NSURLSession sharedSession]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:URL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(data, response, error); + }); + }]; + + [task resume]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index f56d2f3..dff58f1 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -1,13 +1,14 @@ - + - + + - + @@ -15,11 +16,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TalkinToTheNet/TalkinToTheNet/DetailViewController.h b/TalkinToTheNet/TalkinToTheNet/DetailViewController.h new file mode 100644 index 0000000..12894d2 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/DetailViewController.h @@ -0,0 +1,17 @@ +// +// DetailViewController.h +// TalkinToTheNet +// +// Created by Xiulan Shi on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "APIManager.h" +#import "PlaceResult.h" + +@interface DetailViewController : UIViewController + +@property (nonatomic) PlaceResult *place; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/DetailViewController.m b/TalkinToTheNet/TalkinToTheNet/DetailViewController.m new file mode 100644 index 0000000..d83d628 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/DetailViewController.m @@ -0,0 +1,95 @@ +// +// DetailViewController.m +// TalkinToTheNet +// +// Created by Xiulan Shi on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "DetailViewController.h" +#import "MikeInstagramPost.h" + +@interface DetailViewController () +< +UITableViewDataSource, +UITableViewDelegate +> + +@property (weak, nonatomic) IBOutlet UILabel *nameLabel; +@property (weak, nonatomic) IBOutlet UILabel *addressLabel; +@property (weak, nonatomic) IBOutlet UITableView *tableView; +@property (nonatomic) NSMutableArray *instagramPosts; + +@end + +@implementation DetailViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.tableView.dataSource = self; + self.tableView.delegate = self; + self.nameLabel.text = self.place.name; + self.addressLabel.text = self.place.address; + [self fetchInstagramData]; +} + +- (void)fetchInstagramData { + + NSString *tagName = [self.place.name stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSString *url = [NSString stringWithFormat:@"https://api.instagram.com/v1/tags/%@/media/recent?client_id=ac0ee52ebb154199bfabfb15b498c067",tagName]; + // create an instagram url + NSURL *instagramURL = [NSURL URLWithString:url]; + + // fetch data from the instagram endpoint and print json response + [APIManager GETRequestWithURL:instagramURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + NSArray *results = json[@"data"]; + + //reset my array + self.instagramPosts = [[NSMutableArray alloc] init]; + + //loop through all json posts + for (NSDictionary *result in results) { + + //create new post from json + MikeInstagramPost *post = [[MikeInstagramPost alloc] initWithJSON:result]; + + //add post to array + [self.instagramPosts addObject:post]; + + } + + [self.tableView reloadData]; + + }]; + +} + +# pragma mark -tableView delegate methods + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + return self.instagramPosts.count; + +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PostCellIdentifier" forIndexPath:indexPath]; + MikeInstagramPost *post = self.instagramPosts[indexPath.row]; + cell.textLabel.text = post.username; + cell.detailTextLabel.text = post.caption[@"text"]; + return cell; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/Info.plist b/TalkinToTheNet/TalkinToTheNet/Info.plist index 6905cc6..80eba70 100644 --- a/TalkinToTheNet/TalkinToTheNet/Info.plist +++ b/TalkinToTheNet/TalkinToTheNet/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.h b/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.h new file mode 100644 index 0000000..280cb3c --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.h @@ -0,0 +1,22 @@ +// +// MikeInstagramPost.h +// CustomTableViewCells +// +// Created by Xiulan Shi on 9/24/15. +// Copyright © 2015 Xiulan Shi. All rights reserved. +// + +#import + +@interface MikeInstagramPost : NSObject + +@property (nonatomic) NSArray *tags; +@property (nonatomic) NSInteger commentCount; +@property (nonatomic) NSInteger likeCount; +@property (nonatomic) NSString *username; +@property (nonatomic) NSString *fullName; +@property (nonatomic) NSDictionary *caption; + +- (instancetype)initWithJSON:(NSDictionary *)json; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.m b/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.m new file mode 100644 index 0000000..729e099 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/MikeInstagramPost.m @@ -0,0 +1,33 @@ +// +// MikeInstagramPost.m +// CustomTableViewCells +// +// Created by Xiulan Shi on 9/24/15. +// Copyright © 2015 Xiulan Shi. All rights reserved. +// + +#import "MikeInstagramPost.h" + +@implementation MikeInstagramPost + + +- (instancetype)initWithJSON:(NSDictionary *)json { + // If you need to overwrite initialize, this is the code you need + if (self = [super init]) { + + self.tags = json[@"tags"]; + + //self.commentCount = [[[json objectForKey:@"comments"] objectForKey:@"count"] integerValue]; + self.commentCount = [json [@"comments"][@"count"] integerValue]; + self.likeCount = [json [@"likes"][@"count"] integerValue]; + self.caption = json[@"caption"]; + self.username = json[@"user"][@"username"]; + self.fullName = json[@"user"][@"full_name"]; + + return self; + } + return nil; +} + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/PlaceResult.h b/TalkinToTheNet/TalkinToTheNet/PlaceResult.h new file mode 100644 index 0000000..073114b --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/PlaceResult.h @@ -0,0 +1,17 @@ +// +// PlaceResult.h +// TalkinToTheNet +// +// Created by Xiulan Shi on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import + +@interface PlaceResult : NSObject + +@property (nonatomic) NSString *name; +@property (nonatomic) NSString *address; + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/PlaceResult.m b/TalkinToTheNet/TalkinToTheNet/PlaceResult.m new file mode 100644 index 0000000..c05e535 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/PlaceResult.m @@ -0,0 +1,13 @@ +// +// PlaceResult.m +// TalkinToTheNet +// +// Created by Xiulan Shi on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "PlaceResult.h" + +@implementation PlaceResult + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/ViewController.m b/TalkinToTheNet/TalkinToTheNet/ViewController.m index cbefa29..b279a6b 100644 --- a/TalkinToTheNet/TalkinToTheNet/ViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/ViewController.m @@ -7,8 +7,24 @@ // #import "ViewController.h" +#import "APIManager.h" +#import "PlaceResult.h" +#import "DetailViewController.h" + @interface ViewController () +< +UITableViewDataSource, +UITableViewDelegate, +UITextFieldDelegate +> + +@property (weak, nonatomic) IBOutlet UITextField *findTextField; +@property (weak, nonatomic) IBOutlet UITextField *searchPlaceTextField; + +@property (weak, nonatomic) IBOutlet UITableView *tableView; + +@property (nonatomic) NSMutableArray *searchResults; @end @@ -16,9 +32,102 @@ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. + self.tableView.dataSource = self; + self.tableView.delegate = self; + self.searchPlaceTextField.delegate = self; +} + +- (void) makeNewAPIRequestWithSearchTerm:(NSString*)searchTerm andLocation:(NSString*)location + callbackBlock:(void(^)())block{ + + + NSString *urlString = [NSString stringWithFormat:@"https://api.foursquare.com/v2/venues/search?near=%@&query=%@&client_id=SVBBDTUHT5WOBDQ5NINYVTLNDNTHGD0XGRRE0LMB304VMWG1&client_secret=ZHPO4GOAGH3YSPQNQZAYC13YJ420Q2IPXAI0CRHQ0I3SB0HL&v=20150925", location, searchTerm]; + + NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + + NSURL *url = [NSURL URLWithString:encodedString]; + + [APIManager GETRequestWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + if (data != nil) { + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + NSArray *results = json[@"response"][@"venues"]; + + self.searchResults =[[NSMutableArray alloc] init]; + + for (NSDictionary *result in results) { + + NSString *name = result[@"name"]; + NSString *address = result[@"location"][@"address"]; + NSString *city = result[@"location"][@"city"]; + NSString *state = result[@"location"][@"state"]; + NSString *postCode = result[@"location"][@"postalCode"]; + + PlaceResult *placeObject = [[PlaceResult alloc] init]; + placeObject.name = name; + placeObject.address = [NSString stringWithFormat:@"%@, %@, %@ %@", address, city, state, postCode]; + + [self.searchResults addObject:placeObject]; + + } + + block(); + } + + }]; + +} + + +# pragma mark - tableView delegate methods + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + return self.searchResults.count; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier" forIndexPath:indexPath]; + PlaceResult *result = [self.searchResults objectAtIndex:indexPath.row]; + + cell.textLabel.text = result.name; + cell.detailTextLabel.text = result.address; + + return cell; } +# pragma mark - text field delegate methods + +- (BOOL)textFieldShouldReturn:(UITextField *)textField{ + + [self.view endEditing:YES]; + + [self makeNewAPIRequestWithSearchTerm:self.findTextField.text andLocation:textField.text callbackBlock:^{ + [self.tableView reloadData]; + }]; + + return YES; +} + +# pragma mark - segua + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + + PlaceResult *currentPlace = self.searchResults[indexPath.row]; + + DetailViewController *viewController = segue.destinationViewController; + + viewController.place = currentPlace; + +} + + - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.