Created
May 11, 2017 10:00
-
-
Save narikbi/9f9fad1d9d338222e128506f1bd17a75 to your computer and use it in GitHub Desktop.
Example of Objective-C UIViewController class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SearchViewController.m | |
// | |
// | |
// Created by Narikbi | |
// Copyright © 2016. All rights reserved. | |
// | |
#import "SearchViewController.h" | |
#import "VenueApi.h" | |
#import "VenueTableCell.h" | |
#import "PaginatorResponse.h" | |
#import "VenueViewController.h" | |
#import "LocationHelper.h" | |
#import "LoadingFooterView.h" | |
#import "CategoryGroupTableCell.h" | |
#import "SearchTableHeaderView.h" | |
#import "FilterViewController.h" | |
#import "FilterHelper.h" | |
#define kPageName @"Search page" | |
#define kPageId @(2) | |
#define kPerPage 20 | |
@interface SearchViewController () | |
@property (weak, nonatomic) IBOutlet UITableView *tableView; | |
@end | |
@implementation SearchViewController { | |
UIRefreshControl *refreshControl; | |
NSMutableArray *venues; | |
UISearchBar *searchBar; | |
NSInteger currentPage; | |
PaginatorResponse *paginator; | |
BOOL filterChanged; | |
BOOL showHUD; | |
NSString *prevSearch; | |
FilterHelper *filter; | |
} | |
#pragma mark - | |
#pragma mark - Init | |
- (instancetype)init { | |
self = [super init]; | |
if (self) { | |
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Search" bundle:nil]; | |
self = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([self class])]; | |
} | |
return self; | |
} | |
- (void)initVars { | |
venues = [NSMutableArray new]; | |
currentPage = 1; | |
filterChanged = NO; | |
showHUD = YES; | |
prevSearch = @""; | |
filter = [FilterHelper sharedInstance]; | |
} | |
#pragma mark - | |
#pragma mark - Lifecycle | |
- (void)viewDidLoad { | |
[super viewDidLoad]; | |
[self initVars]; | |
[self configUI]; | |
[self loadCategoryGroups]; | |
[self loadVenues]; | |
[self addObservers]; | |
} | |
- (void)viewWillAppear:(BOOL)animated { | |
[super viewWillAppear:animated]; | |
[self configFilterButton]; | |
if (![searchBar.text isEqualToString:filter.searchText]) { | |
filterChanged = YES; | |
searchBar.text = filter.searchText; | |
} | |
} | |
- (void)viewDidAppear:(BOOL)animated { | |
[super viewDidDisappear:animated]; | |
// Start logging GoogleAnalytics | |
[[GANRoutes sharedManager] startWithPage:kPageName]; | |
[AnalyticsKit pageId:kPageId]; | |
// If active tabbar controller | |
if ([self isActiveVC]) { | |
if (filterChanged) { | |
searchBar.text = filter.searchText; | |
currentPage = 1; | |
[self loadVenues]; | |
filterChanged = NO; | |
} | |
} | |
} | |
- (void)addObservers { | |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchFromNotification:) | |
name:kNotificationSearchVenueWithText | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardWillShow:) | |
name:UIKeyboardWillShowNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardWillHide:) | |
name:UIKeyboardWillHideNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(filterApplied) | |
name:kNotificationFilterApplied | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(scrollToTop) | |
name:kNotificationSearchScrollToTop | |
object:nil]; | |
} | |
- (void)dealloc { | |
[[NSNotificationCenter defaultCenter] removeObserver:self]; | |
[[GANRoutes sharedManager] removePage:kPageName]; | |
} | |
#pragma mark - | |
#pragma mark - Actions | |
- (void)filterTapped { | |
FilterViewController *vc = [FilterViewController new]; | |
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc]; | |
[self presentViewController:nc animated:YES completion:nil]; | |
[[GANRoutes sharedManager] action:@"Click on filter button"]; | |
[AnalyticsKit pageId:kPageId actionId:@10]; | |
} | |
- (void)filterApplied { | |
currentPage = 1; | |
__weak typeof(self) wself = self; | |
if ([self isActiveVC]) { | |
[wself loadVenues]; | |
} else { | |
filterChanged = YES; | |
} | |
[[GANRoutes sharedManager] action:@"Filter applied"]; | |
[AnalyticsKit pageId:kPageId actionId:@11]; | |
} | |
#pragma mark - | |
#pragma mark - Loading data | |
- (void)loadFirstPage { | |
currentPage = 1; | |
[self loadVenues]; | |
} | |
- (void)loadVenues { | |
paginator.loaded = NO; | |
if (showHUD) { | |
[SVProgressHUD show]; | |
} else { | |
self.tableView.tableFooterView = [LoadingFooterView footerView]; | |
} | |
// GAN | |
if (searchBar.text.length) { | |
[[GANRoutes sharedManager] action:@"Search by text" label:@"text" value:searchBar.text]; | |
filter.searchText = searchBar.text; | |
} | |
__weak typeof(self) wself = self; | |
[VenueApi getVenuesWithText:searchBar.text cityId:nil sortType:SortTypeRating longitude:nil latitude:nil radius:nil filter:filter page:currentPage perPage:20 success:^(PaginatorResponse * response) { | |
[SVProgressHUD dismiss]; | |
wself.tableView.tableFooterView = nil; | |
[refreshControl endRefreshing]; | |
if (!paginator) { | |
paginator = response; | |
paginator.currentPage = 1; | |
paginator.perPage = kPerPage; | |
paginator.exactMatch = true; | |
} else { | |
paginator.perPage = response.perPage; | |
paginator.totalPage = response.totalPage; | |
paginator.totalItem = response.totalItem; | |
paginator.exactMatch = response.exactMatch; | |
} | |
paginator.loaded = YES; | |
if (currentPage == 1) { | |
[venues removeAllObjects]; | |
} | |
if (paginator.exactMatch) { | |
[wself updateVenueCountLabel]; | |
} else { | |
[wself showNoExactMatch]; | |
} | |
[venues addObjectsFromArray:response.items]; | |
[wself.tableView reloadData]; | |
} failure:^(NSInteger code, NSString *message) { | |
[SVProgressHUD dismiss]; | |
wself.tableView.tableFooterView = nil; | |
[refreshControl endRefreshing]; | |
}]; | |
} | |
#pragma mark - | |
#pragma mark - Search from notification | |
- (void)searchFromNotification:(NSNotification *)not { | |
searchBar.text = not.userInfo[@"text"]; | |
currentPage = 1; | |
showHUD = YES; | |
[self loadVenues]; | |
[[GANRoutes sharedManager] action:@"Search by text" label:@"text" value:not.userInfo[@"text"]]; | |
[AnalyticsKit pageId:kPageId actionId:@12 value:searchBar.text]; | |
} | |
#pragma mark - | |
#pragma mark - UITableView Datasource | |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { | |
return venues.count; | |
} | |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { | |
VenueTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"VenueTableCell"]; | |
[cell setVenue:venues[indexPath.row]]; | |
return cell; | |
} | |
#pragma mark - | |
#pragma mark - UITableView Delegate | |
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { | |
[tableView deselectRowAtIndexPath:indexPath animated:YES]; | |
self.tableView.tableHeaderView = [SearchTableHeaderView viewWithCount:paginator.totalItem]; | |
Venue *v = venues[indexPath.row]; | |
VenueViewController *vc = [VenueViewController new]; | |
[vc setVenueCategoryId:v.venueCategoryId]; | |
[self.navigationController pushViewController:vc animated:YES]; | |
[[GANRoutes sharedManager] action:@"Детали заведения из списка" label:@"venue" value:v.analyticsKey]; | |
[AnalyticsKit pageId:kPageId actionId:@14 value:v.venueCategoryId.stringValue]; | |
if (searchBar.text.length) { | |
if (![prevSearch isEqualToString:searchBar.text]) { | |
prevSearch = searchBar.text; | |
[AnalyticsKit pageId:kPageId actionId:@12 value:searchBar.text]; | |
} | |
[AnalyticsKit pageId:kPageId actionId:@99 value:searchBar.text venueId:v.venueCategoryId]; | |
} | |
} | |
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { | |
return UITableViewAutomaticDimension; | |
} | |
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { | |
NSInteger sections = [tableView numberOfSections]; | |
NSInteger items = [tableView numberOfRowsInSection:indexPath.section]; | |
if ([indexPath section] == sections - 1 && indexPath.item == items - 1) { | |
// Last row | |
if (paginator.loaded && paginator.hasNextPage) { | |
currentPage++; | |
paginator.currentPage = currentPage; | |
self.tableView.tableFooterView = [LoadingFooterView footerView]; | |
showHUD = NO; | |
[self loadVenues]; | |
} | |
} | |
} | |
#pragma mark - | |
#pragma mark - Scroll notification | |
- (void)scrollToTopTable { | |
__weak typeof(self) wself = self; | |
[self performBlock:^{ | |
if ([self.tableView numberOfRowsInSection:0] > 0) { | |
[wself.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; | |
} | |
} afterDelay:.4]; | |
} | |
#pragma mark - | |
#pragma mark - SearchBar Delegate | |
- (void)searchBarTextDidBeginEditing:(UISearchBar *)sb { | |
searchBar.showsCancelButton = YES; | |
} | |
- (void)searchBarCancelButtonClicked:(UISearchBar *)sb { | |
[self.tableView reloadData]; | |
searchBar.showsCancelButton = NO; | |
[searchBar resignFirstResponder]; | |
searchBar.text = @""; | |
currentPage = 1; | |
showHUD = YES; | |
[self loadVenues]; | |
} | |
- (void)searchBarSearchButtonClicked:(UISearchBar *)sb { | |
[sb resignFirstResponder]; | |
showHUD = YES; | |
currentPage = 1; | |
[self loadVenues]; | |
[AnalyticsKit pageId:kPageId actionId:@12 value:searchBar.text]; | |
} | |
#pragma mark - | |
#pragma mark - Keyboard Notifications | |
- (void)keyboardWillShow:(NSNotification *)notification { | |
CGSize keyboardSize = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size; | |
NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]; | |
UIEdgeInsets contentInsets; | |
if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])) { | |
contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0); | |
} else { | |
contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0); | |
} | |
__weak typeof(self) wself = self; | |
[UIView animateWithDuration:rate.floatValue animations:^{ | |
wself.tableView.contentInset = contentInsets; | |
wself.tableView.scrollIndicatorInsets = contentInsets; | |
}]; | |
} | |
- (void)keyboardWillHide:(NSNotification *)notification { | |
NSNumber *rate = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]; | |
__weak typeof(self) wself = self; | |
[UIView animateWithDuration:rate.floatValue animations:^{ | |
wself.tableView.contentInset = UIEdgeInsetsZero; | |
wself.tableView.scrollIndicatorInsets = UIEdgeInsetsZero; | |
}]; | |
} | |
#pragma mark - | |
#pragma mark - ConfigUI | |
- (void)updateVenueCountLabel { | |
self.tableView.tableHeaderView = [SearchTableHeaderView viewWithCount:paginator.totalItem]; | |
} | |
- (void)showNoExactMatch { | |
self.tableView.tableHeaderView = [SearchTableHeaderView viewWithText:@"Unfortunately, there are no places for your requests. 😕\nBut we recommend you to see:"]; | |
} | |
- (void)scrollToTop { | |
[self.tableView setContentOffset:CGPointZero animated:YES]; | |
} | |
- (BOOL)isActiveVC { | |
UINavigationController *nc = self.tabBarController.selectedViewController; | |
return ([nc.viewControllers.lastObject isKindOfClass:[self class]]); | |
} | |
- (void)configFilterButton { | |
if ([[FilterHelper sharedInstance] isEnabled]) { | |
UIBarButtonItem *filterB = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"icFilterActive"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(filterTapped)]; | |
self.navigationItem.rightBarButtonItem = filterB; | |
} else { | |
UIBarButtonItem *filterB = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"icFilterInactive"] style:UIBarButtonItemStylePlain target:self action:@selector(filterTapped)]; | |
self.navigationItem.rightBarButtonItem = filterB; | |
} | |
} | |
- (void)configUI { | |
[self.tableView registerNib:[UINib nibWithNibName:@"VenueTableCell" bundle:nil] forCellReuseIdentifier:@"VenueTableCell"]; | |
[self.tableView registerNib:[UINib nibWithNibName:@"CategoryGroupTableCell" bundle:nil] forCellReuseIdentifier:@"CategoryGroupTableCell"]; | |
searchBar = [UISearchBar new]; | |
searchBar.delegate = self; | |
searchBar.placeholder = @"Search"; | |
self.navigationItem.titleView = searchBar; | |
searchBar.tintColor = [UIColor whiteColor]; | |
self.tableView.estimatedRowHeight = 100; | |
self.tableView.rowHeight = UITableViewAutomaticDimension; | |
self.tableView.delegate = self; | |
self.tableView.dataSource = self; | |
self.tableView.tableFooterView = [UIView new]; | |
refreshControl = [[UIRefreshControl alloc] init]; | |
[refreshControl addTarget:self action:@selector(loadFirstPage) forControlEvents:UIControlEventValueChanged]; | |
[self.tableView addSubview:refreshControl]; | |
} | |
@end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment