Skip to content

Instantly share code, notes, and snippets.

@narikbi
Created May 11, 2017 10:00
Show Gist options
  • Save narikbi/9f9fad1d9d338222e128506f1bd17a75 to your computer and use it in GitHub Desktop.
Save narikbi/9f9fad1d9d338222e128506f1bd17a75 to your computer and use it in GitHub Desktop.
Example of Objective-C UIViewController class.
//
// 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