[ios] New Search

This commit is contained in:
Igor Khmurets 2014-03-16 12:30:58 +03:00 committed by Alex Zolotarev
parent 5f2284c113
commit 03da916506
16 changed files with 1512 additions and 901 deletions

View file

@ -1,5 +1,4 @@
#import "MapViewController.h"
#import "SearchVC.h"
#import "MapsAppDelegate.h"
#import "EAGLView.h"
#import "BookmarksRootVC.h"
@ -19,6 +18,8 @@
#import "InAppMessagesManager.h"
#import "InterstitialView.h"
#import "MoreAppsVC.h"
#import "PlacePageView.h"
#import "SearchView.h"
#import "../Settings/SettingsManager.h"
#import "../../Common/CustomAlertView.h"
@ -42,12 +43,13 @@
const long long PRO_IDL = 510623322L;
const long long LITE_IDL = 431183278L;
@interface MapViewController () <SideToolbarDelegate>
@interface MapViewController () <SideToolbarDelegate, PlacePageViewDelegate, PlacePageVCDelegate>
@property (nonatomic) LocationButton * locationButton;
@property (nonatomic) UINavigationBar * apiNavigationBar;
@property (nonatomic) ShareActionSheet * shareActionSheet;
@property (nonatomic) UIButton * buyButton;
@property (nonatomic) PlacePageView * placePageView;
@property (nonatomic) SearchView * searchView;
@end
@ -142,18 +144,20 @@ const long long LITE_IDL = 431183278L;
#pragma mark - Map Navigation
- (void)positionBallonClickedLat:(double)lat lon:(double)lon
- (void)poiBalloonClicked:(m2::PointD const &)point info:(search::AddressInfo const &)addressInfo
{
CGPoint const p = CGPointMake(MercatorBounds::LonToX(lon), MercatorBounds::LatToY(lat));
PlacePreviewViewController * preview = [[PlacePreviewViewController alloc] initWithPoint:p];
m_popoverPos = p;
[self pushViewController:preview];
[self showPlacePageWithPoint:point addressInfo:addressInfo];
}
- (void)poiBalloonDismissed
{
[self.placePageView setState:PlacePageStateHidden animated:YES];
}
- (void)additionalLayer:(size_t)index
{
Framework & framework = GetFramework();
Bookmark const * bookmark = framework.AdditionalPoiLayerGetBookmark(index);
Bookmark * bookmark = framework.AdditionalPoiLayerGetBookmark(index);
[self.placePageView showBookmark:*bookmark];
[self.placePageView setState:PlacePageStateBitShown animated:YES];
@ -165,12 +169,21 @@ const long long LITE_IDL = 431183278L;
[self.placePageView setState:PlacePageStateBitShown animated:YES];
}
- (void)bookmarkBalloonClicked:(BookmarkAndCategory const &)bmAndCat
- (void)bookmarkBalloonClicked:(BookmarkAndCategory const &)bookmarkAndCategory
{
PlacePageVC * vc = [[PlacePageVC alloc] initWithBookmark:bmAndCat];
Bookmark const * bm = GetFramework().GetBmCategory(bmAndCat.first)->GetBookmark(bmAndCat.second);
m_popoverPos = CGPointMake(bm->GetOrg().x, bm->GetOrg().y);
[self pushViewController:vc];
[self showPlacePageWithBookmarkAndCategory:bookmarkAndCategory];
}
- (void)showPlacePageWithPoint:(m2::PointD)point addressInfo:(search::AddressInfo)addressInfo
{
[self.placePageView showPoint:point addressInfo:addressInfo];
[self.placePageView setState:PlacePageStateBitShown animated:YES];
}
- (void)showPlacePageWithBookmarkAndCategory:(BookmarkAndCategory)bookmarkAndCategory
{
[self.placePageView showBookmarkAndCategory:bookmarkAndCategory];
[self.placePageView setState:PlacePageStateBitShown animated:YES];
}
- (void)onMyPositionClicked:(id)sender
@ -281,26 +294,6 @@ const long long LITE_IDL = 431183278L;
[self invalidate];
}
- (void)showSearchResultAsBookmarkAtMercatorPoint:(const m2::PointD &)pt withInfo:(const search::AddressInfo &)info
{
}
- (void)showBalloonWithCategoryIndex:(int)cat andBookmarkIndex:(int)bm
{
}
- (void)poiBalloonDismissed
{
}
- (void)additionalLayer:(size_t)index
{
}
- (void)updatePointsFromEvent:(UIEvent *)event
{
NSSet * allTouches = [event allTouches];
@ -388,6 +381,8 @@ const long long LITE_IDL = 431183278L;
if (!self.sideToolbar.isMenuHidden)
[self.sideToolbar setMenuHidden:YES animated:YES];
if (self.placePageView.state == PlacePageStateOpened)
[self.placePageView setState:PlacePageStateBitShown animated:YES];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
@ -611,11 +606,21 @@ const long long LITE_IDL = 431183278L;
}
#endif
[self.view addSubview:self.apiNavigationBar];
[self.view addSubview:self.locationButton];
[self.view addSubview:self.searchView];
[self.view addSubview:self.fadeView];
UIButton * slideView = [self slideView];
[self.view addSubview:slideView];
[self.view addSubview:self.placePageView];
[self.view addSubview:self.sideToolbar];
self.sideToolbar.slideView = slideView;
[self.sideToolbar setMenuHidden:YES animated:NO];
}
@ -650,10 +655,10 @@ const long long LITE_IDL = 431183278L;
typedef void (*POSITIONBalloonFnT)(id, SEL, double, double);
typedef void (*POIBalloonFnT)(id, SEL, m2::PointD const &, search::AddressInfo const &);
typedef void (*POIBalloonDismissedFnT)(id, SEL);
typedef void (*APIPOINTBalloonFnT)(id, SEL, url_scheme::ApiPoint const &);
typedef void (*BOOKMARKBalloonFnT)(id, SEL, BookmarkAndCategory const &);
typedef void (*POIBalloonDismissedFnT)(id, SEL);
typedef void (*ADDITIONALLayerFnT)(id, SEL, size_t);
typedef void (*ADDITIONALLayerFnT)(id, SEL, size_t index);
PinClickManager & manager = f.GetBalloonManager();
@ -715,8 +720,8 @@ const long long LITE_IDL = 431183278L;
{
_placePageView = [[PlacePageView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, 0)];
_placePageView.minY = self.view.height;
_placePageView.delegate = self;
_placePageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
_placePageView.delegate = self;
[_placePageView addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
}
return _placePageView;
@ -740,7 +745,7 @@ const long long LITE_IDL = 431183278L;
if (!_locationButton)
{
_locationButton = [[LocationButton alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
_locationButton.center = CGPointMake(28, self.view.height - 28);
_locationButton.center = CGPointMake(28, LOCATION_BUTTON_MID_Y);
_locationButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
[_locationButton addTarget:self action:@selector(onMyPositionClicked:) forControlEvents:UIControlEventTouchUpInside];
}
@ -777,37 +782,44 @@ const long long LITE_IDL = 431183278L;
}
#define SLIDE_VIEW_DARK_PART_TAG 1
#define SLIDE_VIEW_MID_Y (self.view.height - 35)
- (SideToolbar *)sideToolbar
{
if (!_sideToolbar)
{
_sideToolbar = [[SideToolbar alloc] initWithFrame:CGRectMake(self.view.width, 0, 260, self.view.height)];
_sideToolbar = [[SideToolbar alloc] initWithFrame:CGRectMake(self.view.width, 0, 310, self.view.height)];
_sideToolbar.delegate = self;
}
return _sideToolbar;
}
UIButton * toolbarButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 70)];
toolbarButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
toolbarButton.maxX = self.view.width;
toolbarButton.midY = self.view.height - 35;
[toolbarButton addTarget:self action:@selector(toolbarButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- (UIButton *)slideView
{
UIButton * toolbarButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 70)];
toolbarButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
toolbarButton.maxX = self.view.width;
toolbarButton.midY = SLIDE_VIEW_MID_Y;
[toolbarButton addTarget:self action:@selector(toolbarButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
CGFloat tailShift = 7;
CGFloat tailShift = 7;
UIImageView * tailLight = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SlideViewLight"]];
tailLight.maxX = toolbarButton.width;
tailLight.midY = toolbarButton.height / 2 + tailShift;
[toolbarButton addSubview:tailLight];
UIImageView * tailLight = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SlideViewLight"]];
tailLight.maxX = toolbarButton.width;
tailLight.midY = toolbarButton.height / 2 + tailShift;
[toolbarButton addSubview:tailLight];
UIImageView * tailDark = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SlideViewDark"]];
tailDark.maxX = toolbarButton.width;
tailDark.midY = toolbarButton.height / 2 + tailShift;
tailDark.alpha = 0;
tailDark.tag = SLIDE_VIEW_DARK_PART_TAG;
[toolbarButton addSubview:tailDark];
UIImageView * tailDark = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SlideViewDark"]];
tailDark.maxX = toolbarButton.width;
tailDark.midY = toolbarButton.height / 2 + tailShift;
tailDark.alpha = 0;
tailDark.tag = SLIDE_VIEW_DARK_PART_TAG;
[toolbarButton addSubview:tailDark];
[self.view addSubview:toolbarButton];
return toolbarButton;
}
_sideToolbar.slideView = toolbarButton;
#pragma mark - PlacePageViewDelegate
- (void)placePageView:(PlacePageView *)placePage willEditBookmarkAndCategory:(BookmarkAndCategory const &)bookmarkAndCategory
{
@ -819,17 +831,10 @@ const long long LITE_IDL = 431183278L;
- (void)placePageView:(PlacePageView *)placePage willEditBookmarkWithInfo:(search::AddressInfo const &)addressInfo point:(m2::PointD const &)point
{
if (!_apiNavigationBar)
{
CGFloat height = SYSTEM_VERSION_IS_LESS_THAN(@"7") ? 44 : 64;
_apiNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, self.view.width, height)];
UINavigationItem * item = [[UINavigationItem alloc] init];
_apiNavigationBar.items = @[item];
_apiNavigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_apiNavigationBar.topItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"back", nil) style: UIBarButtonItemStyleDone target:self action:@selector(returnToApiApp)];
_apiNavigationBar.alpha = 0;
}
return _apiNavigationBar;
PlacePageVC * vc = [[PlacePageVC alloc] initWithInfo:addressInfo point:CGPointMake(point.x, point.y)];
vc.delegate = self;
vc.mode = PlacePageVCModeEditing;
[self pushViewController:vc];
}
- (void)placePageView:(PlacePageView *)placePage willShareInfo:(search::AddressInfo const &)addressInfo point:(m2::PointD const &)point
@ -847,26 +852,13 @@ const long long LITE_IDL = 431183278L;
#pragma mark - SideToolbarDelegate
- (void)sideToolbar:(SideToolbar *)toolbar didPressButtonAtIndex:(NSInteger)buttonIndex
- (void)sideToolbar:(SideToolbar *)toolbar didPressItemWithName:(NSString *)itemName
{
if (buttonIndex == 0)
{
if (GetPlatform().IsPro())
{
SearchVC * vc = [[SearchVC alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
else
{
[[Statistics instance] logProposalReason:@"Search Screen" withAnswer:@"YES"];
[[UIApplication sharedApplication] openProVersion];
}
}
else if (buttonIndex == 1)
if ([itemName isEqualToString:@"Maps"])
{
[[[MapsAppDelegate theApp] settingsManager] show:self];
}
else if (buttonIndex == 2)
else if ([itemName isEqualToString:@"Bookmarks"])
{
if (GetPlatform().IsPro())
{
@ -879,12 +871,12 @@ const long long LITE_IDL = 431183278L;
[[UIApplication sharedApplication] openProVersion];
}
}
else if (buttonIndex == 3)
else if ([itemName isEqualToString:@"Settings"])
{
SettingsViewController * vc = [self.mainStoryboard instantiateViewControllerWithIdentifier:[SettingsViewController className]];
[self.navigationController pushViewController:vc animated:YES];
}
else if (buttonIndex == 4)
else if ([itemName isEqualToString:@"Share"])
{
CLLocation * location = [MapsAppDelegate theApp].m_locationManager.lastLocation;
if (location)
@ -901,13 +893,41 @@ const long long LITE_IDL = 431183278L;
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"unknown_current_position", nil) message:nil delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil] show];
}
}
else if (buttonIndex == 5)
else if ([itemName isEqualToString:@"MoreApps"])
{
MoreAppsVC * vc = [[MoreAppsVC alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
}
- (void)sideToolbarDidCloseMenu:(SideToolbar *)toolbar
{
[self.view bringSubviewToFront:self.placePageView];
}
- (void)sideToolbarWillCloseMenu:(SideToolbar *)toolbar
{
[UIView animateWithDuration:0.25 animations:^{
if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
[self setNeedsStatusBarAppearanceUpdate];
self.fadeView.alpha = 0;
UIView * darkTail = [self.sideToolbar.slideView viewWithTag:SLIDE_VIEW_DARK_PART_TAG];
darkTail.alpha = 0;
}];
}
- (void)sideToolbarWillOpenMenu:(SideToolbar *)toolbar
{
[UIView animateWithDuration:0.25 animations:^{
if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
[self setNeedsStatusBarAppearanceUpdate];
self.fadeView.alpha = 1;
UIView * darkTail = [self.sideToolbar.slideView viewWithTag:SLIDE_VIEW_DARK_PART_TAG];
darkTail.alpha = 1;
}];
[self.view sendSubviewToBack:self.placePageView];
}
- (void)sideToolbarDidUpdateShift:(SideToolbar *)toolbar
{
self.fadeView.alpha = toolbar.menuShift / (toolbar.maximumMenuShift - toolbar.minimumMenuShift);
@ -955,15 +975,13 @@ const long long LITE_IDL = 431183278L;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == self.sideToolbar && [keyPath isEqualToString:@"isMenuHidden"])
if (object == self.searchView && [keyPath isEqualToString:@"active"])
{
[UIView animateWithDuration:0.25 animations:^{
if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)])
[self setNeedsStatusBarAppearanceUpdate];
self.fadeView.alpha = self.sideToolbar.isMenuHidden ? 0 : 1;
UIView * darkTail = [self.sideToolbar.slideView viewWithTag:SLIDE_VIEW_DARK_PART_TAG];
darkTail.alpha = self.sideToolbar.isMenuHidden ? 0 : 1;
[UIView animateWithDuration:0.2 animations:^{
self.sideToolbar.slideView.maxX = self.searchView.active ? self.view.width + self.sideToolbar.slideView.width : self.view.width;
}];
if (self.searchView.active)
[self.placePageView setState:PlacePageStateHidden animated:YES];
}
else if (object == self.placePageView && [keyPath isEqualToString:@"state"])
{

View file

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
@protocol SearchActivityProtocol <NSObject>
- (void)setActive:(BOOL)active animated:(BOOL)animated;
@property (nonatomic, readonly) BOOL active;
@end

View file

@ -0,0 +1,22 @@
#import <UIKit/UIKit.h>
#import "SearchActivityProtocol.h"
@class SearchBar;
@protocol SearchBarDelegate <NSObject>
- (void)searchBarDidPressCancelButton:(SearchBar *)searchBar;
- (void)searchBarDidPressClearButton:(SearchBar *)searchBar;
@end
@interface SearchBar : UIView <SearchActivityProtocol>
@property (nonatomic, readonly) UITextField * textField;
@property (nonatomic) BOOL isShowingResult;
@property (nonatomic, weak) id <SearchBarDelegate> delegate;
@property (nonatomic) NSString * apiText;
- (void)setSearching:(BOOL)searching;
@end

View file

@ -0,0 +1,349 @@
#import "SearchBar.h"
#import "UIKitCategories.h"
#import "Framework.h"
@interface SearchSpotView : UIView
- (void)setAnimating:(BOOL)animating;
@end
@interface SearchSpotView ()
@property (nonatomic) UIImageView * spotImageView;
@property (nonatomic) UIActivityIndicatorView * activityView;
@property (nonatomic) NSTimer * timer;
@end
@implementation SearchSpotView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self addSubview:self.activityView];
[self addSubview:self.spotImageView];
return self;
}
- (void)setAnimating:(BOOL)animating
{
if (animating)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.15 target:self selector:@selector(timerSelector) userInfo:nil repeats:NO];
}
else
{
[self.activityView stopAnimating];
self.spotImageView.hidden = NO;
[self.timer invalidate];
}
}
- (void)timerSelector
{
[self.activityView startAnimating];
self.spotImageView.hidden = YES;
}
- (UIActivityIndicatorView *)activityView
{
if (!_activityView)
{
_activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityView.center = CGPointMake(self.width / 2, self.height / 2);
}
return _activityView;
}
- (UIImageView *)spotImageView
{
if (!_spotImageView)
{
_spotImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SearchBarIcon"]];
_spotImageView.center = CGPointMake(self.width / 2, self.height / 2);
}
return _spotImageView;
}
@end
@interface SearchBar ()
@property (nonatomic) UITextField * textField;
@property (nonatomic) SearchSpotView * searchImageView;
@property (nonatomic) UILabel * searchLabel;
@property (nonatomic) UIImageView * backgroundImageView;
@property (nonatomic) UIButton * clearButton;
@property (nonatomic) UIButton * cancelButton;
@end
@implementation SearchBar
@synthesize active = _active;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self addSubview:self.backgroundImageView];
self.clearButton.midY = self.backgroundImageView.height / 2;
self.clearButton.maxX = self.backgroundImageView.width;
[self.backgroundImageView addSubview:self.clearButton];
[self addSubview:self.searchImageView];
[self addSubview:self.searchLabel];
self.textField.midY = self.backgroundImageView.height / 2;
CGFloat fieldOffsetL = 39;
CGFloat fieldOffsetR = 24;
self.textField.frame = CGRectMake(fieldOffsetL, self.textField.origin.y, self.backgroundImageView.width - fieldOffsetL - fieldOffsetR, self.textField.height);
[self.backgroundImageView addSubview:self.textField];
self.cancelButton.midY = self.backgroundImageView.height / 2;
[self addSubview:self.cancelButton];
[self setActive:NO animated:NO];
if ([UITextField instancesRespondToSelector:@selector(setTintColor:)])
[[UITextField appearance] setTintColor:[UIColor darkGrayColor]];
return self;
}
- (void)layoutSubviews
{
[self performAfterDelay:0 block:^{
if (!self.active)
[self layoutImageAndLabelInNonActiveState];
}];
}
- (void)setSearching:(BOOL)searching
{
self.searchImageView.animating = searching;
}
#define LABEL_MIN_X 23
- (void)setActive:(BOOL)active animated:(BOOL)animated
{
CGFloat backgroundImageOffset = 10;
if (active)
{
[UIView animateWithDuration:(animated ? 0.1 : 0) delay:0.1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.textField.alpha = 1;
} completion:nil];
[UIView animateWithDuration:(animated ? 0.35 : 0) delay:0 damping:0.8 initialVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
if (self.isShowingResult)
{
self.searchLabel.minX = 47;
}
else
{
CGFloat spaceBetween = self.searchLabel.minX - self.searchImageView.minX;
self.searchImageView.minX = LABEL_MIN_X;
self.searchLabel.minX = self.searchImageView.minX + spaceBetween;
}
self.searchImageView.alpha = 1;
self.searchLabel.alpha = 0;
self.backgroundImageView.frame = CGRectMake(backgroundImageOffset, 0, self.width - backgroundImageOffset - self.cancelButton.width, self.backgroundImageView.height);
self.cancelButton.alpha = 1;
self.cancelButton.maxX = self.width;
self.clearButton.alpha = 1;
} completion:nil];
[self performAfterDelay:0.1 block:^{
[self.textField becomeFirstResponder];
}];
}
else
{
[UIView animateWithDuration:(animated ? 0.1 : 0) animations:^{
self.textField.alpha = 0;
}];
[UIView animateWithDuration:(animated ? 0.45 : 0) delay:0 damping:0.8 initialVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.backgroundImageView.frame = CGRectMake(backgroundImageOffset, 0, self.width - 2 * backgroundImageOffset, self.backgroundImageView.height);
self.searchLabel.text = self.isShowingResult ? self.textField.text : NSLocalizedString(@"search", nil);
[self.searchLabel sizeToFit];
[self layoutImageAndLabelInNonActiveState];
self.cancelButton.alpha = 0;
self.cancelButton.minX = self.width;
if (!self.isShowingResult)
self.clearButton.alpha = 0;
[self.textField resignFirstResponder];
} completion:nil];
}
_active = active;
}
- (void)layoutImageAndLabelInNonActiveState
{
self.searchLabel.alpha = 1;
if (self.isShowingResult)
{
self.searchLabel.midX = self.searchLabel.superview.width / 2;
self.searchImageView.alpha = 0;
self.searchImageView.minX = LABEL_MIN_X;
self.searchLabel.width = MIN(self.searchLabel.width, self.backgroundImageView.width - 54);
}
else
{
CGFloat width = self.searchImageView.width + 8 + self.searchLabel.width;
self.searchImageView.midY = self.backgroundImageView.height / 2;
self.searchImageView.minX = self.backgroundImageView.width / 2 - width / 2 + self.backgroundImageView.minX;
self.searchImageView.alpha = 1;
self.searchLabel.midY = self.backgroundImageView.height / 2;
self.searchLabel.maxX = self.backgroundImageView.width / 2 + width / 2 + self.backgroundImageView.minX;
}
}
- (void)cancelButtonPressed:(id)sender
{
[self.delegate searchBarDidPressCancelButton:self];
}
- (void)clearButtonPressed:(id)sender
{
Framework & framework = GetFramework();
GetFramework().ClearMapApiPoints();
if (self.active)
{
self.textField.text = nil;
self.isShowingResult = NO;
[self.textField becomeFirstResponder];
}
else
{
[self hideSearchedText];
}
[self.delegate searchBarDidPressClearButton:self];
framework.GetBookmarkManager().AdditionalPoiLayerClear();
framework.GetBalloonManager().RemovePin();
framework.GetBalloonManager().Dismiss();
framework.Invalidate();
}
- (void)hideSearchedText
{
self.textField.text = nil;
self.isShowingResult = NO;
self.searchLabel.text = NSLocalizedString(@"search", nil);
[self.searchLabel sizeToFit];
[UIView animateWithDuration:0.4 delay:0 damping:0.8 initialVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self layoutImageAndLabelInNonActiveState];
self.clearButton.alpha = 0;
} completion:nil];
}
- (void)setApiText:(NSString *)apiText
{
if (apiText)
{
self.textField.text = apiText;
self.isShowingResult = YES;
[self setActive:NO animated:YES];
self.clearButton.alpha = 1;
}
else if (_apiText)
{
[self hideSearchedText];
GetFramework().ClearMapApiPoints();
}
_apiText = apiText;
}
- (UILabel *)searchLabel
{
if (!_searchLabel)
{
_searchLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 25)];
_searchLabel.textColor = [UIColor blackColor];
_searchLabel.backgroundColor = [UIColor clearColor];
_searchLabel.textAlignment = NSTextAlignmentLeft;
_searchLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:15];
}
return _searchLabel;
}
- (SearchSpotView *)searchImageView
{
if (!_searchImageView)
{
_searchImageView = [[SearchSpotView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
_searchImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
}
return _searchImageView;
}
- (UIButton *)cancelButton
{
if (!_cancelButton)
{
_cancelButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 64, 44)];
_cancelButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;
_cancelButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:15];
[_cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[_cancelButton setTitle:NSLocalizedString(@"cancel", nil) forState:UIControlStateNormal];
[_cancelButton addTarget:self action:@selector(cancelButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
return _cancelButton;
}
- (UIButton *)clearButton
{
if (!_clearButton)
{
_clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 32, 44)];
_clearButton.contentMode = UIViewContentModeCenter;
_clearButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[_clearButton setImage:[UIImage imageNamed:@"SearchBarClearButton"] forState:UIControlStateNormal];
[_clearButton addTarget:self action:@selector(clearButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
return _clearButton;
}
- (UIImageView *)backgroundImageView
{
if (!_backgroundImageView)
{
UIImage * image = [[UIImage imageNamed:@"SearchBarInactiveBackground"] resizableImageWithCapInsets:UIEdgeInsetsMake(6, 6, 6, 6)];
_backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.width, image.size.height)];
_backgroundImageView.image = image;
_backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_backgroundImageView.userInteractionEnabled = YES;
}
return _backgroundImageView;
}
- (UITextField *)textField
{
if (!_textField)
{
_textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, self.width, 22)];
_textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_textField.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:15];
_textField.returnKeyType = UIReturnKeySearch;
}
return _textField;
}
@end

View file

@ -1,12 +1,15 @@
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, SearchCellPosition) {
SearchCellPositionFirst = 1,
SearchCellPositionMiddle = 2,
SearchCellPositionLast = 3,
SearchCellPositionAlone = 4,
};
@interface SearchCell : UITableViewCell
@property (nonatomic, readonly) UILabel * featureName;
@property (nonatomic, readonly) UILabel * featureType;
@property (nonatomic, readonly) UILabel * featureCountry;
@property (nonatomic, readonly) UILabel * featureDistance;
- (id)initWithReuseIdentifier:(NSString *)identifier;
@property (nonatomic) SearchCellPosition position;
@end

View file

@ -0,0 +1,99 @@
#import "SearchCell.h"
#import "UIKitCategories.h"
@interface SearchCell ()
@property (nonatomic) UIImageView * separatorImageView;
@property (nonatomic) UIImageView * backgroundImageView;
@end
@implementation SearchCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
self.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self addSubview:self.backgroundImageView];
[self.contentView addSubview:self.separatorImageView];
return self;
}
- (void)setPosition:(SearchCellPosition)position
{
if (position == _position)
return;
UIImage * image;
switch (position)
{
case SearchCellPositionFirst:
image = [UIImage imageNamed:@"SearchCellBackgroundTop"];
break;
case SearchCellPositionMiddle:
image = [UIImage imageNamed:@"SearchCellBackgroundMiddle"];
break;
case SearchCellPositionLast:
image = [UIImage imageNamed:@"SearchCellBackgroundBottom"];
break;
case SearchCellPositionAlone:
image = [UIImage imageNamed:@"SearchCellBackgroundAlone"];
break;
}
self.backgroundImageView.image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(6, 6, 6, 6)];
_position = position;
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
self.backgroundImageView.alpha = highlighted ? 0.5 : 1;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.backgroundImageView.alpha = selected ? 0.5 : 1;
}
- (void)layoutSubviews
{
self.backgroundImageView.size = CGSizeMake(self.width - 28, self.height);
self.backgroundImageView.midX = self.width / 2;
[self sendSubviewToBack:self.backgroundImageView];
self.contentView.frame = self.backgroundImageView.frame;
self.separatorImageView.width = self.contentView.width;
self.separatorImageView.maxY = self.contentView.height;
self.separatorImageView.midX = self.contentView.width / 2;
self.separatorImageView.hidden = (self.position == SearchCellPositionLast || self.position == SearchCellPositionAlone);
}
- (UIImageView *)backgroundImageView
{
if (!_backgroundImageView)
{
_backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
}
return _backgroundImageView;
}
- (UIImageView *)separatorImageView
{
if (!_separatorImageView)
{
UIImage * image = [[UIImage imageNamed:@"SearchCellSeparator"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 40, 0, 40)];
_separatorImageView = [[UIImageView alloc] initWithImage:image];
_separatorImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
}
return _separatorImageView;
}
@end

View file

@ -1,79 +0,0 @@
#import "SearchCell.h"
@implementation SearchCell
- (id)initWithReuseIdentifier:(NSString *)identifier
{
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
if (self)
{
// Fonts and sizes are hard-coded because they can't be easily retrieved
UIFont * large = [UIFont fontWithName:@"Helvetica-Bold" size:[UIFont labelFontSize] + 1];
UIFont * small = [UIFont fontWithName:@"Helvetica" size:[UIFont systemFontSize]];
_featureName = [[UILabel alloc] init];
_featureName.font = large;
_featureType = [[UILabel alloc] init];
_featureType.font = small;
_featureType.textColor = [UIColor grayColor];
_featureType.textAlignment = UITextAlignmentRight;
_featureCountry = [[UILabel alloc] init];
_featureCountry.font = small;
_featureCountry.textColor = [UIColor grayColor];
_featureDistance = [[UILabel alloc] init];
_featureDistance.font = small;
_featureDistance.textColor = [UIColor grayColor];
_featureDistance.textAlignment = UITextAlignmentRight;
[self.contentView addSubview:_featureName];
[self.contentView addSubview:_featureType];
[self.contentView addSubview:_featureCountry];
[self.contentView addSubview:_featureDistance];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect r = self.contentView.bounds;
// Leave some experimentally choosen paddings
CGFloat const KPaddingX = 9.0;
CGFloat const KPaddingBottom = 1.0;
r.origin.x += KPaddingX;
r.size.width -= 2 * KPaddingX;
r.size.height -= KPaddingBottom;
// Labels on the right should always fit and be visible, but not more than half of the cell
CGFloat const w = r.size.width;
CGFloat const h = r.size.height;
CGFloat const yDelim = (int)(r.origin.y + h / 5 * 3);
CGFloat xTopDelim = (int)(r.origin.x + w / 2);
CGFloat xBottomDelim = xTopDelim;
if ([_featureDistance.text length])
{
CGSize const distanceTextSize = [_featureDistance.text sizeWithFont:_featureDistance.font];
if (xTopDelim + distanceTextSize.width < r.origin.x + w)
xTopDelim = r.origin.x + w - distanceTextSize.width - KPaddingX;
}
else // Sometimes distance is not available, so use full cell length for the name
{
xTopDelim = r.origin.x + w - KPaddingX;
}
_featureName.frame = CGRectMake(r.origin.x, r.origin.y, xTopDelim - r.origin.x, yDelim - r.origin.y);
_featureDistance.frame = CGRectMake(xTopDelim, r.origin.y, r.origin.x + w - xTopDelim, yDelim - r.origin.y);
if ([_featureType.text length])
{
CGSize const typeTextSize = [_featureType.text sizeWithFont:_featureType.font];
if (xBottomDelim + typeTextSize.width < r.origin.x + w)
xBottomDelim = r.origin.x + w - typeTextSize.width - KPaddingX;
}
_featureCountry.frame = CGRectMake(r.origin.x, yDelim, xBottomDelim - r.origin.x, r.origin.y + h - yDelim);
_featureType.frame = CGRectMake(xBottomDelim, yDelim, r.origin.x + w - xBottomDelim, r.origin.y + h - yDelim);
}
@end

View file

@ -0,0 +1,13 @@
#import <UIKit/UIKit.h>
#import "SearchCell.h"
@interface SearchUniversalCell : SearchCell
@property (nonatomic, readonly) UILabel * titleLabel;
@property (nonatomic, readonly) UILabel * subtitleLabel;
@property (nonatomic, readonly) UILabel * distanceLabel;
+ (CGFloat)cellHeightWithTitle:(NSString *)title subtitle:(NSString *)subtitle viewWidth:(CGFloat)width;
@end

View file

@ -0,0 +1,93 @@
#import "SearchUniversalCell.h"
#import "UIKitCategories.h"
@interface SearchUniversalCell ()
@property (nonatomic) UILabel * titleLabel;
@property (nonatomic) UILabel * subtitleLabel;
@property (nonatomic) UILabel * distanceLabel;
@end
@implementation SearchUniversalCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.subtitleLabel];
[self.contentView addSubview:self.distanceLabel];
return self;
}
#define TITLE_FONT [UIFont fontWithName:@"HelveticaNeue-Light" size:15]
#define TITLE_WIDTH_REST 150
#define TITLE_HEIGHT 60
- (void)layoutSubviews
{
[super layoutSubviews];
self.distanceLabel.maxX = self.width - 45;
self.distanceLabel.midY = self.height / 2 - 0.5;
self.titleLabel.width = self.width - TITLE_WIDTH_REST;
self.titleLabel.minX = 16;
[self.titleLabel sizeToFit];
if ([self.subtitleLabel.text length])
self.titleLabel.minY = 5;
else
self.titleLabel.midY = self.height / 2 - 1.5;
self.subtitleLabel.origin = CGPointMake(self.titleLabel.minX, self.titleLabel.maxY - 1);
}
+ (CGFloat)cellHeightWithTitle:(NSString *)title subtitle:(NSString *)subtitle viewWidth:(CGFloat)width
{
return MAX(44, [title sizeWithDrawSize:CGSizeMake(width - TITLE_WIDTH_REST, TITLE_HEIGHT) font:TITLE_FONT].height + ([subtitle length] ? 27 : 15));
}
- (UILabel *)distanceLabel
{
if (!_distanceLabel)
{
_distanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 70, 16)];
_distanceLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
_distanceLabel.backgroundColor = [UIColor clearColor];
_distanceLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:15];
_distanceLabel.textColor = [UIColor blackColor];
_distanceLabel.textAlignment = NSTextAlignmentRight;
_distanceLabel.alpha = 0.5;
}
return _distanceLabel;
}
- (UILabel *)subtitleLabel
{
if (!_subtitleLabel)
{
_subtitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 190, 16)];
_subtitleLabel.backgroundColor = [UIColor clearColor];
_subtitleLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:10];
_subtitleLabel.textColor = [UIColor colorWithColorCode:@"666666"];
}
return _subtitleLabel;
}
- (UILabel *)titleLabel
{
if (!_titleLabel)
{
_titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, TITLE_HEIGHT)];
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.font = TITLE_FONT;
_titleLabel.textColor = [UIColor blackColor];
_titleLabel.numberOfLines = 0;
_titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
return _titleLabel;
}
@end

View file

@ -1,24 +0,0 @@
#import <UIKit/UIKit.h>
#import "LocationManager.h"
#import "ScopeView.h"
class Framework;
@interface SearchVC : UIViewController
<UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource,
LocationObserver>
{
Framework * m_framework;
LocationManager * m_locationManager;
UITableView * m_table;
// Zero when suggestions cells are not visible
NSInteger m_suggestionsCount;
NSArray * categoriesNames;
}
@property (nonatomic) NSMutableArray * searchResults;
@property (nonatomic) UISearchBar * searchBar;
@property (nonatomic) ScopeView * scopeView;
@end

View file

@ -1,681 +0,0 @@
#import "SearchVC.h"
#import "CompassView.h"
#import "LocationManager.h"
#import "SearchCell.h"
#import "BookmarksVC.h"
#import "CustomNavigationView.h"
#import "MapsAppDelegate.h"
#import "MapViewController.h"
#import "Statistics.h"
#import "Config.h"
#import "UIKitCategories.h"
#include "Framework.h"
#include "../../search/result.hpp"
#include "../../search/params.hpp"
#include "../../indexer/mercator.hpp"
#include "../../platform/platform.hpp"
#include "../../platform/preferred_languages.hpp"
#include "../../platform/settings.hpp"
#include "../../geometry/angles.hpp"
#include "../../geometry/distance_on_sphere.hpp"
/// When to display compass instead of country flags
#define MIN_COMPASS_DISTANCE 25000.0
/// To save search scope selection between launches
#define SEARCH_MODE_SETTING "SearchMode"
SearchVC * g_searchVC = nil;
@interface ResultsWrapper : NSObject
{
search::Results m_results;
}
// Stores search string which corresponds to these results.
@property(nonatomic, retain) NSString * searchString;
- (id)initWithResults:(search::Results const &)res;
- (int)getCount;
- (search::Result const &)getWithPosition:(NSInteger)pos;
- (BOOL)isEndMarker;
- (BOOL)isEndedNormal;
@end
@implementation ResultsWrapper
@synthesize searchString;
- (id)initWithResults:(search::Results const &)res
{
if ((self = [super init]))
m_results = res;
return self;
}
- (int)getCount
{
return static_cast<int>(m_results.GetCount());
}
- (search::Result const &)getWithPosition:(NSInteger)pos
{
return m_results.GetResult(pos);
}
- (BOOL)isEndMarker
{
return m_results.IsEndMarker();
}
- (BOOL)isEndedNormal
{
return m_results.IsEndedNormal();
}
@end
// Last search results are stored between SearchVC sessions
// to appear instantly for the user, they also store last search text query.
//ResultsWrapper * g_lastSearchResults = nil;
static NSInteger GetDefaultSearchScope()
{
NSInteger value;
if (Settings::Get(SEARCH_MODE_SETTING, value))
return value;
return 0; // 0 is default scope ("Near me")
}
NSString * g_lastSearchRequest = nil;
NSInteger g_scopeSection = GetDefaultSearchScope();
NSInteger g_numberOfRowsInEmptySearch = 0;
static void OnSearchResultCallback(search::Results const & res)
{
if (g_searchVC)
{
ResultsWrapper * w = [[ResultsWrapper alloc] initWithResults:res];
[g_searchVC performSelectorOnMainThread:@selector(addResult:)
withObject:w waitUntilDone:NO];
}
}
/////////////////////////////////////////////////////////////////////
@interface SearchVC ()
@property (nonatomic) BOOL searching;
@property (nonatomic) UIActivityIndicatorView * activityIndicator;
@end
@implementation SearchVC
@synthesize searchResults = _searchResults;
- (id)init
{
if ((self = [super initWithNibName:nil bundle:nil]))
{
m_framework = &GetFramework();
m_locationManager = [MapsAppDelegate theApp].m_locationManager;
double lat, lon;
bool const hasPt = [m_locationManager getLat:lat Lon:lon];
m_framework->PrepareSearch(hasPt, lat, lon);
//mycode init array of categories
categoriesNames = [[NSArray alloc] initWithObjects:
@"food",
@"shop",
@"hotel",
@"tourism",
@"entertainment",
@"atm",
@"bank",
@"transport",
@"fuel",
@"parking",
@"pharmacy",
@"hospital",
@"toilet",
@"post",
@"police",
nil];
_searchResults = [[NSMutableArray alloc] initWithObjects:[[ResultsWrapper alloc] init], [[ResultsWrapper alloc] init], [[ResultsWrapper alloc] init], nil];
if (!g_lastSearchRequest)
{
g_lastSearchRequest = @"";
}
}
return self;
}
- (void)fillSearchParams:(search::SearchParams &)params withText:(NSString *)queryString
{
params.m_query = [[queryString precomposedStringWithCompatibilityMapping] UTF8String];
params.m_callback = bind(&OnSearchResultCallback, _1);
// Set current keyboard input mode
// Note: input mode was introduced in iOS 4.2 (now we support 4.3+)
params.SetInputLanguage([[UITextInputMode currentInputMode].primaryLanguage UTF8String]);
double lat, lon;
if ([m_locationManager getLat:lat Lon:lon])
params.SetPosition(lat, lon);
}
- (UISearchBar *)searchBar
{
if (!_searchBar)
{
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.width - 80, 44)];
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchBar.delegate = self;
_searchBar.placeholder = NSLocalizedString(@"search_map", @"Search box placeholder text");
_searchBar.barStyle = UISearchBarStyleDefault;
_searchBar.tintColor = [[UINavigationBar appearance] tintColor];
if (g_lastSearchRequest)
[_searchBar setText:g_lastSearchRequest];
}
return _searchBar;
}
- (ScopeView *)scopeView
{
if (!_scopeView)
{
UISegmentedControl * segmentedControl = [[UISegmentedControl alloc] initWithItems:@[NSLocalizedString(@"search_mode_nearme", nil),
NSLocalizedString(@"search_mode_viewport", nil),
NSLocalizedString(@"search_mode_all", nil)]];
CGFloat width = IPAD ? 400 : 310;
segmentedControl.frame = CGRectMake(0, 0, width, 32);
if (SYSTEM_VERSION_IS_LESS_THAN(@"7"))
segmentedControl.tintColor = [[UINavigationBar appearance] tintColor];
else
segmentedControl.tintColor = [UIColor whiteColor];
segmentedControl.selectedSegmentIndex = GetDefaultSearchScope();
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
[segmentedControl addTarget:self action:@selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
_scopeView = [[ScopeView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, 44) segmentedControl:segmentedControl];
_scopeView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
if (SYSTEM_VERSION_IS_LESS_THAN(@"7"))
_scopeView.backgroundColor = [[UINavigationBar appearance] tintColor];
else
_scopeView.backgroundColor = [UIColor colorWithColorCode:@"28384b"];
}
return _scopeView;
}
- (void)segmentedControlValueChanged:(UISegmentedControl *)segmentedControl
{
g_scopeSection = segmentedControl.selectedSegmentIndex;
// Save selected search mode for future launches
Settings::Set(SEARCH_MODE_SETTING, g_scopeSection);
[self proceedSearchWithString:self.searchBar.text andForceSearch:YES];
}
- (void)viewDidLoad
{
g_searchVC = self;
m_table = [[UITableView alloc] initWithFrame:self.view.bounds];
m_table.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
m_table.delegate = self;
m_table.dataSource = self;
m_table.contentInset = UIEdgeInsetsMake(self.scopeView.height, 0, 0, 0);
m_table.scrollIndicatorInsets = m_table.contentInset;
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:m_table];
[self.view addSubview:self.scopeView];
self.navigationItem.titleView = self.searchBar;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[m_locationManager start:self];
[self performAfterDelay:0 block:^{
[self resizeNavigationBar];
}];
}
- (void)resizeNavigationBar
{
if (SYSTEM_VERSION_IS_LESS_THAN(@"6") || IPAD)
return;
CGFloat landscapeHeight = 32;
CGFloat portraitHeight = 44;
self.navigationController.navigationBar.height = portraitHeight;
if (UIDeviceOrientationIsLandscape(self.interfaceOrientation))
m_table.minY = portraitHeight - landscapeHeight;
else
m_table.minY = 0;
self.scopeView.minY = m_table.minY;
}
- (void)viewDidAppear:(BOOL)animated
{
// Relaunch search when view has appeared because of search indicator hack
// (we replace one control with another, and system calls unsupported method on it)
if (GetPlatform().IsPro())
[self proceedSearchWithString:g_lastSearchRequest andForceSearch:YES];
[self.searchBar becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated
{
[m_locationManager stop:self];
// hide keyboard immediately
[self.searchBar resignFirstResponder];
[super viewWillDisappear:animated];
g_numberOfRowsInEmptySearch = 0;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
{
[self resizeNavigationBar];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES; // All orientations are supported.
}
//**************************************************************************
//*********** SearchBar handlers *******************************************
- (void)searchBar:(UISearchBar *)sender textDidChange:(NSString *)searchText
{
self.searching = [searchText length] > 0;
g_lastSearchRequest = [[NSString alloc] initWithString:self.searchBar.text];
[self clearCacheResults];
[self proceedSearchWithString:self.searchBar.text andForceSearch:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
- (void)onCloseButton:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
//*********** End of SearchBar handlers *************************************
//***************************************************************************
- (void)setSearchBoxText:(NSString *)text
{
self.searchBar.text = text;
// Manually send text change notification if control has no focus,
// OR if iOS 6 - it doesn't send textDidChange notification after text property update
if (![self.searchBar isFirstResponder]
|| [UIDevice currentDevice].systemVersion.floatValue > 5.999)
[self searchBar:self.searchBar textDidChange:text];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
m_suggestionsCount = self.searchBar.text.length ? 0 : 1;
//No text in search show categories
if (m_suggestionsCount)
{
return [categoriesNames count];
}
//If no results we should show 0 strings if search is in progress or 1 string with message thaht there is no results
if (![[_searchResults objectAtIndex:g_scopeSection] getCount])
{
return g_numberOfRowsInEmptySearch;
}
return [[_searchResults objectAtIndex:g_scopeSection] getCount];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger realRowIndex = indexPath.row;
if (m_suggestionsCount)
{
static NSString *CellIdentifier = @"categoryCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = NSLocalizedString([categoriesNames objectAtIndex:indexPath.row], nil);
cell.imageView.image = [UIImage imageNamed:[categoriesNames objectAtIndex:indexPath.row]];
return cell;
}
//No search results
if ([self.searchBar.text length] != 0 && ![[_searchResults objectAtIndex:g_scopeSection] getCount] && g_numberOfRowsInEmptySearch)
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"NoResultsCell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"NoResultsCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.textLabel.text = NSLocalizedString(@"no_search_results_found", nil);
// check if we have no position in "near me" screen
if (![m_locationManager lastLocationIsValid] && g_scopeSection == 0)
cell.detailTextLabel.text = NSLocalizedString(@"unknown_current_position", nil);
else
cell.detailTextLabel.text = @"";
return cell;
}
if ([_searchResults objectAtIndex:g_scopeSection] == nil || realRowIndex >= (NSInteger)[[_searchResults objectAtIndex:g_scopeSection] getCount])
{
ASSERT(false, ("Invalid m_results with size", [[_searchResults objectAtIndex:g_scopeSection] getCount]));
return nil;
}
search::Result const & r = [[_searchResults objectAtIndex:g_scopeSection] getWithPosition:realRowIndex];
if (r.GetResultType() != search::Result::RESULT_SUGGESTION)
{
SearchCell * cell = (SearchCell *)[tableView dequeueReusableCellWithIdentifier:@"FeatureCell"];
if (!cell)
cell = [[SearchCell alloc] initWithReuseIdentifier:@"FeatureCell"];
// Init common parameters
cell.featureName.text = [NSString stringWithUTF8String:r.GetString()];
cell.featureCountry.text = [NSString stringWithUTF8String:r.GetRegionString()];
cell.featureType.text = [NSString stringWithUTF8String:r.GetFeatureType()];
// Get current position and compass "north" direction
double azimut = -1.0;
double lat, lon;
if ([m_locationManager getLat:lat Lon:lon])
{
double north = -1.0;
[m_locationManager getNorthRad:north];
string distance;
if (!m_framework->GetDistanceAndAzimut(r.GetFeatureCenter(),
lat, lon, north, distance, azimut))
{
// do not draw arrow for far away features
azimut = -1.0;
}
cell.featureDistance.text = [NSString stringWithUTF8String:distance.c_str()];
}
else
cell.featureDistance.text = nil;
// Show flags only if it has one and no azimut to feature
char const * flag = r.GetRegionFlag();
if (flag && azimut < 0.0)
{
UIImage * flagImage = [UIImage imageNamed:[NSString stringWithFormat:@"%s.png", flag]];
UIImageView * imgView = [[UIImageView alloc] initWithImage:flagImage];
cell.accessoryView = imgView;
}
else
{
// Try to reuse existing compass view
CompassView * compass;
if ([cell.accessoryView isKindOfClass:[CompassView class]])
compass = (CompassView *)cell.accessoryView;
else
{
// Create compass view
float const h = (int)(m_table.rowHeight * 0.6);
compass = [[CompassView alloc] initWithFrame:CGRectMake(0, 0, h, h)];
cell.accessoryView = compass;
}
// Show arrow for valid azimut and if feature is not a continent (flag is exist)
compass.showArrow = (azimut >= 0.0 && flag) ? YES : NO;
compass.angle = azimut;
}
return cell;
}
else
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"SuggestionCell"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SuggestionCell"];
cell.textLabel.text = [NSString stringWithUTF8String:r.GetString()];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger realRowIndex = indexPath.row;
// Suggestion cell was clicked
if (m_suggestionsCount)
{
[[Statistics instance] logEvent:@"Category Selection" withParameters:@{@"Category" : [categoriesNames objectAtIndex:realRowIndex]}];
[self setSearchBoxText:[NSLocalizedString([categoriesNames objectAtIndex:realRowIndex], Search Suggestion) stringByAppendingString:@" "]];
[m_table scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
return;
}
if (realRowIndex < (NSInteger)[[_searchResults objectAtIndex:g_scopeSection] getCount])
{
search::Result const & res = [[_searchResults objectAtIndex:g_scopeSection] getWithPosition:realRowIndex];
if (res.GetResultType() != search::Result::RESULT_SUGGESTION)
{
m_framework->ShowSearchResult(res);
search::AddressInfo info;
info.MakeFrom(res);
if (g_scopeSection == 0)
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"Near Me"}];
else if (g_scopeSection == 1)
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"On the Screen"}];
else
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"Everywhere"}];
[[MapsAppDelegate theApp].m_mapViewController showSearchResultAsBookmarkAtMercatorPoint:res.GetFeatureCenter() withInfo:info];
[self onCloseButton:nil];
}
else
{
[self setSearchBoxText:[NSString stringWithUTF8String:res.GetSuggestionString()]];
// Remove blue selection from the row
[tableView deselectRowAtIndexPath: indexPath animated:YES];
}
}
}
- (void)setSearching:(BOOL)searching
{
if (searching)
[self.activityIndicator startAnimating];
else
[self.activityIndicator stopAnimating];
_searching = searching;
}
- (UIActivityIndicatorView *)activityIndicator
{
if (!_activityIndicator)
{
_activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
_activityIndicator.center = CGPointMake(self.searchBar.width - 45, self.searchBar.height / 2);
_activityIndicator.backgroundColor = [UIColor whiteColor];
[self.searchBar addSubview:_activityIndicator];
}
return _activityIndicator;
}
// Called on UI thread from search threads
- (void)addResult:(id)res
{
ResultsWrapper * w = (ResultsWrapper *)res;
if ([w isEndMarker])
{
if ([w isEndedNormal])
{
g_numberOfRowsInEmptySearch = 1;
self.searching = NO;
[m_table reloadData];
}
}
else
{
g_numberOfRowsInEmptySearch = 0;
[_searchResults replaceObjectAtIndex:g_scopeSection withObject:w];
[m_table reloadData];
}
}
void setSearchType(search::SearchParams & params)
{
switch (g_scopeSection)
{
case 0:
params.SetSearchMode(search::SearchParams::AROUND_POSITION);
break;
case 1:
params.SetSearchMode(search::SearchParams::IN_VIEWPORT);
break;
case 2:
params.SetSearchMode(search::SearchParams::ALL);
break;
default:
params.SetSearchMode(search::SearchParams::ALL);
break;
}
}
//******************************************************************
//*********** Location manager callbacks ***************************
- (void)onLocationError:(location::TLocationError)errorCode
{
// Handle location status changes if necessary
}
- (void)onLocationUpdate:(location::GpsInfo const &)info
{
// Refresh search results with newer location.
if (![self.searchBar.text length])
return;
search::SearchParams params;
setSearchType(params);
if (self.searchBar.text)
{
[self fillSearchParams:params withText:self.searchBar.text];
// hack, fillSearch Params return invalid position
params.SetPosition(info.m_latitude, info.m_longitude);
g_numberOfRowsInEmptySearch = m_framework->Search(params) ? 0 : 1;
}
}
- (void)onCompassUpdate:(location::CompassInfo const &)info
{
double lat, lon;
if (![m_locationManager getLat:lat Lon:lon])
return;
//check if categories are on the screen
if (!m_suggestionsCount && [[_searchResults objectAtIndex:g_scopeSection] getCount])
{
double const northRad = (info.m_trueHeading < 0) ? info.m_magneticHeading : info.m_trueHeading;
NSArray * cells = m_table.visibleCells;
for (NSUInteger i = 0; i < cells.count; ++i)
{
UITableViewCell * cell = (UITableViewCell *)[cells objectAtIndex:i];
NSInteger realRowIndex = [m_table indexPathForCell:cell].row;
search::Result const & res = [[_searchResults objectAtIndex:g_scopeSection] getWithPosition:realRowIndex];
if (res.GetResultType() != search::Result::RESULT_SUGGESTION)
{
// Show compass only for cells without flags
if ([cell.accessoryView isKindOfClass:[CompassView class]])
{
CompassView * compass = (CompassView *)cell.accessoryView;
m2::PointD const center = res.GetFeatureCenter();
compass.angle = ang::AngleTo(m2::PointD(MercatorBounds::LonToX(lon),
MercatorBounds::LatToY(lat)), center) + northRad;
}
}
}
}
}
//*********** End of Location manager callbacks ********************
//******************************************************************
// Dismiss virtual keyboard when touching tableview
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.searchBar resignFirstResponder];
}
// Dismiss virtual keyboard when "Search" button is pressed
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self.searchBar resignFirstResponder];
}
// Callback from suggestion cell, called when icon is selected
- (void)onSuggestionSelected:(NSString *)suggestion
{
[self setSearchBoxText:[suggestion stringByAppendingString:@" "]];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self onCloseButton:nil];
}
- (void)clearCacheResults
{
for (int i = 0; i < [_searchResults count]; ++i)
{
[_searchResults replaceObjectAtIndex:i withObject:[[ResultsWrapper alloc] init]];
}
}
- (void)proceedSearchWithString:(NSString *)searchText andForceSearch:(BOOL)forceSearch
{
g_numberOfRowsInEmptySearch = 0;
[m_table reloadData];
if (![searchText length])
return;
search::SearchParams params;
setSearchType(params);
if (forceSearch)
{
params.SetForceSearch(true);
}
[self fillSearchParams:params withText:searchText];
if (!m_framework->Search(params))
{
g_numberOfRowsInEmptySearch = 1;
[m_table reloadData];
}
}
@end

View file

@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>
#import "SearchActivityProtocol.h"
#import "SearchBar.h"
@interface SearchView : UIView <SearchActivityProtocol>
@property (nonatomic) SearchBar * searchBar;
@end

View file

@ -0,0 +1,574 @@
#import "SearchView.h"
#import "SegmentedControl.h"
#import "SearchUniversalCell.h"
#import "UIKitCategories.h"
#import "MapsAppDelegate.h"
#import "LocationManager.h"
#import "Statistics.h"
#import "MapViewController.h"
#import "LocationManager.h"
#include "Framework.h"
#include "../../search/result.hpp"
#include "../../search/params.hpp"
#include "../../indexer/mercator.hpp"
#include "../../platform/platform.hpp"
#include "../../platform/preferred_languages.hpp"
#include "../../platform/settings.hpp"
#include "../../geometry/angles.hpp"
#include "../../geometry/distance_on_sphere.hpp"
@interface SearchResultsWrapper : NSObject
- (id)initWithResults:(search::Results const &)res;
- (search::Result const &)resultWithPosition:(NSInteger)position;
- (NSInteger)count;
- (BOOL)isEndMarker;
- (BOOL)isEndedNormal;
@end
@interface SearchResultsWrapper ()
@property (nonatomic) search::Results results;
@property (nonatomic) NSMutableDictionary * distances;
@end
@implementation SearchResultsWrapper
- (id)initWithResults:(search::Results const &)results
{
self = [super init];
self.results = results;
return self;
}
- (NSMutableDictionary *)distances
{
if (!_distances)
_distances = [[NSMutableDictionary alloc] init];
return _distances;
}
- (NSInteger)count
{
return self.results.GetCount();
}
- (search::Result const &)resultWithPosition:(NSInteger)position
{
return self.results.GetResult(position);
}
- (BOOL)isEndMarker
{
return self.results.IsEndMarker();
}
- (BOOL)isEndedNormal
{
return self.results.IsEndedNormal();
}
@end
@interface SearchView () <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, SearchBarDelegate, SegmentedControlDelegate, LocationObserver>
@property (nonatomic) SegmentedControl * segmentedControl;
@property (nonatomic) UITableView * tableView;
@property (nonatomic) UIView * backgroundView;
@property (nonatomic) UIImageView * topBackgroundView;
@property (nonatomic) UILabel * emptyResultLabel;
- (BOOL)isShowingCategories;
@property (nonatomic) NSMutableArray * searchData;
@property (nonatomic) NSArray *categoriesNames;
@end
@implementation SearchView
@synthesize active = _active;
__weak SearchView * selfPointer;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self addSubview:self.backgroundView];
[self addSubview:self.tableView];
[self addSubview:self.topBackgroundView];
[self addSubview:self.segmentedControl];
[self addSubview:self.searchBar];
[self addSubview:self.emptyResultLabel];
self.emptyResultLabel.center = CGPointMake(self.width / 2, 160);
self.emptyResultLabel.hidden = YES;
self.searchBar.midX = self.width / 2;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(barTapped:)];
[self.searchBar addGestureRecognizer:tap];
NSInteger value;
self.segmentedControl.selectedSegmentIndex = Settings::Get("SearchMode", value) ? value : 0;
self.segmentedControl.midX = self.width / 2;
[self setActive:NO animated:NO];
selfPointer = self;
double latitude;
double longitude;
LocationManager * locationManager = [MapsAppDelegate theApp].m_locationManager;
bool const hasPt = [locationManager getLat:latitude Lon:longitude];
GetFramework().PrepareSearch(hasPt, latitude, longitude);
[locationManager start:self];
return self;
}
- (void)onLocationError:(location::TLocationError)errorCode
{
NSLog(@"Location error in SearchView");
}
- (void)onLocationUpdate:(location::GpsInfo const &)info
{
if ([self.searchBar.textField.text length])
{
search::SearchParams params = [self searchParameters];
params.SetPosition(info.m_latitude, info.m_longitude);
GetFramework().Search(params);
[self recalculateDistances];
[self.tableView reloadRowsAtIndexPaths:self.tableView.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationNone];
}
}
- (void)recalculateDistances
{
LocationManager * locationManager = [MapsAppDelegate theApp].m_locationManager;
double north = -1.0;
double azimut = -1.0;
[locationManager getNorthRad:north];
double lat, lon;
if ([locationManager getLat:lat Lon:lon])
{
for (NSInteger segment = 0; segment < [self.segmentedControl segmentsCount]; segment++) {
SearchResultsWrapper * wrapper = self.searchData[segment];
for (NSInteger position = 0; position < [wrapper count]; position++) {
search::Result const & result = [wrapper resultWithPosition:position];
string distance;
GetFramework().GetDistanceAndAzimut(result.GetFeatureCenter(), lat, lon, north, distance, azimut);
wrapper.distances[@(position)] = [NSString stringWithUTF8String:distance.c_str()];
}
}
}
}
- (void)onCompassUpdate:(location::CompassInfo const &)info
{
}
- (search::SearchParams)searchParameters
{
NSInteger scopeIndex = self.segmentedControl.selectedSegmentIndex;
search::SearchParams params;
if (scopeIndex == 0)
params.SetSearchMode(search::SearchParams::AROUND_POSITION);
else if (scopeIndex == 1)
params.SetSearchMode(search::SearchParams::IN_VIEWPORT);
else if (scopeIndex == 2)
params.SetSearchMode(search::SearchParams::ALL);
params.m_query = [[self.searchBar.textField.text precomposedStringWithCompatibilityMapping] UTF8String];
params.m_callback = bind(&OnSearchResultCallback, _1);
params.SetInputLanguage([[UITextInputMode currentInputMode].primaryLanguage UTF8String]);
params.SetForceSearch(true);
return params;
}
- (void)search
{
self.emptyResultLabel.hidden = YES;
[self.searchBar setSearching:YES];
search::SearchParams params = [self searchParameters];
double lat, lon;
if ([[MapsAppDelegate theApp].m_locationManager getLat:lat Lon:lon])
params.SetPosition(lat, lon);
GetFramework().Search(params);
[self.tableView reloadData];
}
static void OnSearchResultCallback(search::Results const & results)
{
SearchResultsWrapper * wrapper = [[SearchResultsWrapper alloc] initWithResults:results];
[selfPointer performSelectorOnMainThread:@selector(frameworkDidAddSearchResult:) withObject:wrapper waitUntilDone:NO];
}
- (void)frameworkDidAddSearchResult:(SearchResultsWrapper *)wrapper
{
if ([wrapper isEndMarker])
{
if ([wrapper isEndedNormal])
{
[self.searchBar setSearching:NO];
[self recalculateDistances];
[self.tableView reloadData];
}
}
else
{
self.emptyResultLabel.hidden = [self isShowingCategories] ? YES : ([wrapper count] > 0);
self.searchData[self.segmentedControl.selectedSegmentIndex] = wrapper;
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:YES];
}
}
- (void)searchBarDidPressClearButton:(SearchBar *)searchBar
{
[self processTextChanging];
}
- (void)searchBarDidPressCancelButton:(id)searchBar
{
[self setActive:NO animated:YES];
}
- (void)setActive:(BOOL)active animated:(BOOL)animated
{
[self.searchBar setActive:active animated:animated];
[self.segmentedControl setActive:active animated:animated];
if (active)
{
[UIView animateWithDuration:(animated ? 0.4 : 0) delay:0 damping:0.9 initialVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.backgroundView.alpha = 1;
self.topBackgroundView.alpha = 1;
self.tableView.alpha = 1;
self.tableView.minY = 0;
} completion:^(BOOL finished){
[self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:YES];
}];
}
else
{
[UIView animateWithDuration:(animated ? 0.4 : 0) delay:0 damping:0.9 initialVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.backgroundView.alpha = 0;
self.topBackgroundView.alpha = 0;
self.tableView.alpha = 0;
self.tableView.minY = self.height;
} completion:nil];
}
[self willChangeValueForKey:@"active"];
_active = active;
[self didChangeValueForKey:@"active"];
}
- (void)barTapped:(UITapGestureRecognizer *)sender
{
[self setActive:YES animated:YES];
}
- (void)textFieldTextChanged:(id)sender
{
[self processTextChanging];
}
- (void)processTextChanging
{
if ([self isShowingCategories])
{
self.emptyResultLabel.hidden = YES;
[self.tableView reloadData];
}
else
{
[self search];
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField.text length] > 0;
}
- (void)segmentedControl:(SegmentedControl *)segmentControl didSelectSegment:(NSInteger)segmentIndex
{
[self search];
}
- (CGFloat)defaultSearchBarMinY
{
if (SYSTEM_VERSION_IS_LESS_THAN(@"7"))
return self.width < self.height ? 10 : 4;
else
return self.width < self.height ? 30 : 20;
}
- (void)layoutSubviews
{
self.searchBar.minY = [self defaultSearchBarMinY];
if (self.width < self.height)
{
self.segmentedControl.minY = self.searchBar.maxY - 4;
self.segmentedControl.height = 40;
self.topBackgroundView.height = self.segmentedControl.maxY + 3;
}
else
{
self.segmentedControl.minY = self.searchBar.maxY - 6;
self.segmentedControl.height = 27;
self.topBackgroundView.height = self.segmentedControl.maxY + 1;
}
self.tableView.contentInset = UIEdgeInsetsMake(self.topBackgroundView.maxY + 13.5, 0, 14, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(self.topBackgroundView.maxY, 0, 0, 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SearchUniversalCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UniversalCell"];
if (!cell)
cell = [[SearchUniversalCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UniversalCell"];
if ([self isShowingCategories])
{
cell.titleLabel.text = NSLocalizedString(self.categoriesNames[indexPath.row], nil);
cell.subtitleLabel.text = nil;
cell.distanceLabel.text = nil;
}
else
{
if (indexPath.row == 0)
{
cell.titleLabel.text = @"Показать все";
cell.subtitleLabel.text = nil;
cell.distanceLabel.text = nil;
}
else
{
SearchResultsWrapper * wrapper = self.searchData[self.segmentedControl.selectedSegmentIndex];
NSInteger position = indexPath.row - 1;
search::Result const & result = [wrapper resultWithPosition:position];
cell.titleLabel.text = [NSString stringWithUTF8String:result.GetString()];
cell.subtitleLabel.text = result.GetRegionString() ? [NSString stringWithUTF8String:result.GetRegionString()] : nil;
cell.distanceLabel.text = wrapper.distances[@(position)];
}
}
if ([self rowsCount] == 1)
cell.position = SearchCellPositionAlone;
else if (indexPath.row == 0)
cell.position = SearchCellPositionFirst;
else if (indexPath.row == [self rowsCount] - 1)
cell.position = SearchCellPositionLast;
else
cell.position = SearchCellPositionMiddle;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isShowingCategories])
{
return [SearchUniversalCell cellHeightWithTitle:self.categoriesNames[indexPath.row] subtitle:nil viewWidth:tableView.width];
}
else
{
if (indexPath.row == 0)
{
return [SearchUniversalCell cellHeightWithTitle:@"Показать все" subtitle:nil viewWidth:tableView.width];
}
else
{
SearchResultsWrapper * wrapper = self.searchData[self.segmentedControl.selectedSegmentIndex];
NSInteger position = indexPath.row - 1;
search::Result const & result = [wrapper resultWithPosition:position];
NSString * title = [NSString stringWithUTF8String:result.GetString()];
NSString * subtitle = [NSString stringWithUTF8String:result.GetRegionString()];
return [SearchUniversalCell cellHeightWithTitle:title subtitle:subtitle viewWidth:tableView.width];
}
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self rowsCount];
}
- (NSInteger)rowsCount
{
SearchResultsWrapper * wrapper = self.searchData[self.segmentedControl.selectedSegmentIndex];
NSInteger resultsCount = [wrapper count] ? [wrapper count] + 1 : 0;
return [self isShowingCategories] ? [self.categoriesNames count] : resultsCount;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([self isShowingCategories])
{
[[Statistics instance] logEvent:@"Category Selection" withParameters:@{@"Category" : self.categoriesNames[indexPath.row]}];
self.searchBar.textField.text = [NSLocalizedString(self.categoriesNames[indexPath.row], nil) stringByAppendingString:@" "];
[self search];
return;
}
if (indexPath.row == 0)
{
GetFramework().ShowAllSearchResults();
self.searchBar.isShowingResult = YES;
[self setActive:NO animated:YES];
}
else
{
NSInteger segmentIndex = self.segmentedControl.selectedSegmentIndex;
NSInteger position = indexPath.row - 1;
search::Result const & result = [self.searchData[segmentIndex] resultWithPosition:position];
if (result.GetResultType() == search::Result::RESULT_SUGGESTION)
{
self.searchBar.textField.text = [NSString stringWithUTF8String:result.GetSuggestionString()];
[self search];
return;
}
else
{
GetFramework().ShowSearchResult(result);
if (segmentIndex == 0)
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"Near Me"}];
else if (segmentIndex == 1)
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"On the Screen"}];
else
[[Statistics instance] logEvent:@"Search Filter" withParameters:@{@"Filter Name" : @"Everywhere"}];
self.searchBar.textField.text = [NSString stringWithUTF8String:result.GetString()];
self.searchBar.isShowingResult = YES;
[self setActive:NO animated:YES];
}
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (!scrollView.decelerating && scrollView.dragging)
[self.searchBar.textField resignFirstResponder];
}
- (BOOL)isShowingCategories
{
return ![self.searchBar.textField.text length];
}
- (NSMutableArray *)searchData
{
if (!_searchData)
_searchData = [@[[[SearchResultsWrapper alloc] init], [[SearchResultsWrapper alloc] init], [[SearchResultsWrapper alloc] init]] mutableCopy];
return _searchData;
}
- (NSArray *)categoriesNames
{
if (!_categoriesNames)
_categoriesNames = @[@"food", @"shop", @"hotel", @"tourism", @"entertainment", @"atm", @"bank", @"transport", @"fuel", @"parking", @"pharmacy", @"hospital", @"toilet", @"post", @"police",];
return _categoriesNames;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return CGRectContainsPoint(self.searchBar.frame, point) || self.active;
}
- (UITableView *)tableView
{
if (!_tableView)
{
_tableView = [[UITableView alloc] initWithFrame:self.bounds];
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return _tableView;
}
- (UIImageView *)topBackgroundView
{
if (!_topBackgroundView)
{
_topBackgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.width, 0)];
_topBackgroundView.image = [[UIImage imageNamed:@"SearchViewTopBackground"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 0, 10, 0)];
_topBackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_topBackgroundView.userInteractionEnabled = YES;
}
return _topBackgroundView;
}
- (UIView *)backgroundView
{
if (!_backgroundView)
{
_backgroundView = [[UIView alloc] initWithFrame:self.bounds];
_backgroundView.backgroundColor = [UIColor colorWithColorCode:@"efeff4"];
_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
return _backgroundView;
}
- (SegmentedControl *)segmentedControl
{
if (!_segmentedControl)
{
_segmentedControl = [[SegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 294, 0)];
_segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
_segmentedControl.delegate = self;
}
return _segmentedControl;
}
- (SearchBar *)searchBar
{
if (!_searchBar)
{
_searchBar = [[SearchBar alloc] initWithFrame:CGRectMake(0, 0, self.width, 44)];
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchBar.textField.delegate = self;
_searchBar.delegate = self;
[_searchBar.textField addTarget:self action:@selector(textFieldTextChanged:) forControlEvents:UIControlEventEditingChanged];
}
return _searchBar;
}
- (UILabel *)emptyResultLabel
{
if (!_emptyResultLabel)
{
_emptyResultLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.width, 60)];
_emptyResultLabel.backgroundColor = [UIColor clearColor];
_emptyResultLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14];
_emptyResultLabel.text = @"Нет результатов";
_emptyResultLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
_emptyResultLabel.textAlignment = NSTextAlignmentCenter;
}
return _emptyResultLabel;
}
@end

View file

@ -0,0 +1,21 @@
#import <UIKit/UIKit.h>
#import "SearchActivityProtocol.h"
@class SegmentedControl;
@protocol SegmentedControlDelegate <NSObject>
- (void)segmentedControl:(SegmentedControl *)segmentControl didSelectSegment:(NSInteger)segmentIndex;
@end
@interface SegmentedControl : UIView <SearchActivityProtocol>
- (void)setActive:(BOOL)active animated:(BOOL)animated;
@property (nonatomic) NSInteger selectedSegmentIndex;
@property (nonatomic) id <SegmentedControlDelegate> delegate;
- (NSInteger)segmentsCount;
@end

View file

@ -0,0 +1,144 @@
#import "SegmentedControl.h"
#import "UIKitCategories.h"
@interface SegmentedControl ()
@property (nonatomic, readonly) UIButton * selectedButton;
@property (nonatomic) UIImageView * selectionImageView;
@property (nonatomic) UIButton * leftButton;
@property (nonatomic) UIButton * centerButton;
@property (nonatomic) UIButton * rightButton;
@end
@implementation SegmentedControl
@synthesize active = _active;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self addSubview:self.selectionImageView];
self.leftButton = [self buttonWithTitle:NSLocalizedString(@"search_mode_nearme", nil)];
self.leftButton.tag = 0;
self.centerButton = [self buttonWithTitle:NSLocalizedString(@"search_mode_viewport", nil)];
self.centerButton.tag = 1;
self.rightButton = [self buttonWithTitle:NSLocalizedString(@"search_mode_all", nil)];
self.rightButton.tag = 2;
[self setSelectedButton:self.leftButton animated:NO];
[self setActive:NO animated:NO];
return self;
}
- (NSInteger)segmentsCount
{
return 3;
}
- (UIButton *)buttonWithTitle:(NSString *)title
{
UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 90, 44)];
[button setTitle:[title lowercaseString] forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithColorCode:@"333333"] forState:UIControlStateNormal];
[button setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
[button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
button.midY = self.height / 2;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;;
button.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14];
[self addSubview:button];
return button;
}
- (UIImageView *)selectionImageView
{
if (!_selectionImageView)
{
_selectionImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SegmentSelection"]];
_selectionImageView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
}
return _selectionImageView;
}
- (void)setActive:(BOOL)active animated:(BOOL)animated
{
if (active)
{
[UIView animateWithDuration:(animated ? 0.35 : 0) delay:0 damping:0.8 initialVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSInteger count = 3;
CGFloat start = (self.width / count) / 2;
CGFloat delta = self.width / count;
self.leftButton.midX = start;
self.centerButton.midX = start + delta;
self.rightButton.midX = start + 2 * delta;
self.selectionImageView.center = self.selectedButton.center;
self.leftButton.alpha = 1;
self.centerButton.alpha = 1;
self.rightButton.alpha = 1;
self.selectionImageView.alpha = 1;
} completion:^(BOOL finished){}];
}
else
{
[UIView animateWithDuration:(animated ? 0.4 : 0) delay:0 damping:0.8 initialVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.leftButton.maxX = 0;
self.rightButton.minX = self.width;
self.centerButton.midX = self.width / 2;
self.selectionImageView.center = self.selectedButton.center;
self.leftButton.alpha = 0;
self.centerButton.alpha = 0;
self.rightButton.alpha = 0;
self.selectionImageView.alpha = 0;
} completion:^(BOOL finished){}];
}
_active = active;
}
- (void)layoutSubviews
{
self.selectionImageView.center = self.selectedButton.center;
}
- (NSInteger)selectedSegmentIndex
{
return self.selectedButton.tag;
}
- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex
{
if (selectedSegmentIndex == 0)
[self setSelectedButton:self.leftButton animated:NO];
else if (selectedSegmentIndex == 1)
[self setSelectedButton:self.centerButton animated:NO];
else if (selectedSegmentIndex == 2)
[self setSelectedButton:self.rightButton animated:NO];
}
- (void)setSelectedButton:(UIButton *)selectedButton animated:(BOOL)animated
{
_selectedButton.selected = NO;
_selectedButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14];
_selectedButton.userInteractionEnabled = YES;
selectedButton.selected = YES;
selectedButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:14];
selectedButton.userInteractionEnabled = NO;
[UIView animateWithDuration:(animated ? 0.3 : 0) delay:0 damping:0.8 initialVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.selectionImageView.center = selectedButton.center;
} completion:^(BOOL finished){}];
_selectedButton = selectedButton;
}
- (void)buttonPressed:(UIButton *)sender
{
[self setSelectedButton:sender animated:YES];
[self.delegate segmentedControl:self didSelectSegment:sender.tag];
}
@end

View file

@ -61,6 +61,18 @@
978F9248183B6671000D6C7C /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 978F9246183B6671000D6C7C /* Main_iPhone.storyboard */; };
978F9253183BD530000D6C7C /* NavigationController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 978F9252183BD530000D6C7C /* NavigationController.mm */; };
978F9254183BD530000D6C7C /* NavigationController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 978F9252183BD530000D6C7C /* NavigationController.mm */; };
97A8000C18B21363000C07A2 /* SearchView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97A8000B18B21363000C07A2 /* SearchView.mm */; };
97A8000D18B21363000C07A2 /* SearchView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97A8000B18B21363000C07A2 /* SearchView.mm */; };
97A8001018B21395000C07A2 /* SearchBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97A8000F18B21395000C07A2 /* SearchBar.mm */; };
97A8001118B21395000C07A2 /* SearchBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97A8000F18B21395000C07A2 /* SearchBar.mm */; };
97A8001418B2140A000C07A2 /* SearchUniversalCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8001318B2140A000C07A2 /* SearchUniversalCell.m */; };
97A8001518B2140A000C07A2 /* SearchUniversalCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8001318B2140A000C07A2 /* SearchUniversalCell.m */; };
97A8001C18B25497000C07A2 /* SegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8001B18B25497000C07A2 /* SegmentedControl.m */; };
97A8001D18B25497000C07A2 /* SegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8001B18B25497000C07A2 /* SegmentedControl.m */; };
97A8002718B2741C000C07A2 /* SearchCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8002618B2741C000C07A2 /* SearchCell.m */; };
97A8002818B2741C000C07A2 /* SearchCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A8002618B2741C000C07A2 /* SearchCell.m */; };
97ABBA4518C8DF620079333C /* PlacePageView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97ABBA4418C8DF620079333C /* PlacePageView.mm */; };
97ABBA4618C8DF620079333C /* PlacePageView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97ABBA4418C8DF620079333C /* PlacePageView.mm */; };
97C9851E186AE3C500AF7E9E /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C9851C186AE3C500AF7E9E /* Reachability.m */; };
97C9851F186AE3C500AF7E9E /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C9851C186AE3C500AF7E9E /* Reachability.m */; };
97C98522186AE3CF00AF7E9E /* AppInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97C98520186AE3CF00AF7E9E /* AppInfo.mm */; };
@ -286,7 +298,6 @@
FA054612155C465E001F4E37 /* SelectSetVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA054611155C465E001F4E37 /* SelectSetVC.mm */; };
FA054613155C465E001F4E37 /* SelectSetVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA054611155C465E001F4E37 /* SelectSetVC.mm */; };
FA065FED128614C400FEA989 /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = FA065FEC128614C400FEA989 /* MainWindow-iPad.xib */; };
FA09E01113F71F6C007E69CA /* SearchVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA09E01013F71F6C007E69CA /* SearchVC.mm */; };
FA140651162A6288002BC1ED /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA14064D162A6288002BC1ED /* empty@2x.png */; };
FA140652162A6288002BC1ED /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA14064D162A6288002BC1ED /* empty@2x.png */; };
FA140653162A6288002BC1ED /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = FA14064E162A6288002BC1ED /* empty.png */; };
@ -312,7 +323,6 @@
FA765AB51737BC6D00279CFF /* 64-lite.png in Resources */ = {isa = PBXBuildFile; fileRef = FA765AB11737BC6D00279CFF /* 64-lite.png */; };
FA765AB61737BC6D00279CFF /* 320-lite.png in Resources */ = {isa = PBXBuildFile; fileRef = FA765AB21737BC6D00279CFF /* 320-lite.png */; };
FA7F4B0017F1FFE800FAB1B5 /* World.mwm in Resources */ = {isa = PBXBuildFile; fileRef = FAFF42291347F101009BBB14 /* World.mwm */; };
FA81AE3314D061BF00A0D70D /* SearchCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA81AE3214D061BF00A0D70D /* SearchCell.mm */; };
FA85F633145DDDC20090E1A0 /* packed_polygons.bin in Resources */ = {isa = PBXBuildFile; fileRef = FA85F632145DDDC20090E1A0 /* packed_polygons.bin */; };
FA87151B12B1518F00592DAF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA87151A12B1518F00592DAF /* SystemConfiguration.framework */; };
FA8F8938132D5DB00048E3FE /* libtomcrypt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA8F8937132D5DB00048E3FE /* libtomcrypt.a */; };
@ -1378,11 +1388,9 @@
FAFB08F0151215EE0041901D /* RenderContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = EE7F297E1219ECA300EB67A9 /* RenderContext.mm */; };
FAFB08F1151215EE0041901D /* WebViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAFCB63513366E78001A5C59 /* WebViewController.mm */; };
FAFB08F2151215EE0041901D /* CustomAlertView.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA34BEC81338D72F00FFB2A7 /* CustomAlertView.mm */; };
FAFB08F3151215EE0041901D /* SearchVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA09E01013F71F6C007E69CA /* SearchVC.mm */; };
FAFB08F4151215EE0041901D /* CompassView.mm in Sources */ = {isa = PBXBuildFile; fileRef = FABF223D13FAA97A003D4D49 /* CompassView.mm */; };
FAFB08F5151215EE0041901D /* Preferences.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA29FDA9141E77F8004ADF66 /* Preferences.mm */; };
FAFB08F6151215EE0041901D /* LocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA5C2A1144F135F005337F6 /* LocationManager.mm */; };
FAFB08F8151215EE0041901D /* SearchCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA81AE3214D061BF00A0D70D /* SearchCell.mm */; };
FAFB08FB151215EE0041901D /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EE12020311CD464100ABDD5D /* libfreetype.a */; };
FAFB08FC151215EE0041901D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
FAFB08FD151215EE0041901D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
@ -1467,6 +1475,19 @@
978F9246183B6671000D6C7C /* Main_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main_iPhone.storyboard; sourceTree = "<group>"; };
978F9251183BD530000D6C7C /* NavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigationController.h; sourceTree = "<group>"; };
978F9252183BD530000D6C7C /* NavigationController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NavigationController.mm; sourceTree = "<group>"; };
97A8000A18B21363000C07A2 /* SearchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchView.h; sourceTree = "<group>"; };
97A8000B18B21363000C07A2 /* SearchView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchView.mm; sourceTree = "<group>"; };
97A8000E18B21395000C07A2 /* SearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchBar.h; sourceTree = "<group>"; };
97A8000F18B21395000C07A2 /* SearchBar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchBar.mm; sourceTree = "<group>"; };
97A8001218B2140A000C07A2 /* SearchUniversalCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchUniversalCell.h; sourceTree = "<group>"; };
97A8001318B2140A000C07A2 /* SearchUniversalCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchUniversalCell.m; sourceTree = "<group>"; };
97A8001A18B25497000C07A2 /* SegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SegmentedControl.h; sourceTree = "<group>"; };
97A8001B18B25497000C07A2 /* SegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SegmentedControl.m; sourceTree = "<group>"; };
97A8002518B2741C000C07A2 /* SearchCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchCell.h; sourceTree = "<group>"; };
97A8002618B2741C000C07A2 /* SearchCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchCell.m; sourceTree = "<group>"; };
97A8002918B51238000C07A2 /* SearchActivityProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchActivityProtocol.h; sourceTree = "<group>"; };
97ABBA4318C8DF620079333C /* PlacePageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlacePageView.h; sourceTree = "<group>"; };
97ABBA4418C8DF620079333C /* PlacePageView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlacePageView.mm; sourceTree = "<group>"; };
97C9851C186AE3C500AF7E9E /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
97C9851D186AE3C500AF7E9E /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
97C98520186AE3CF00AF7E9E /* AppInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppInfo.mm; sourceTree = "<group>"; };
@ -1779,8 +1800,6 @@
FA054610155C465E001F4E37 /* SelectSetVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectSetVC.h; path = Bookmarks/SelectSetVC.h; sourceTree = SOURCE_ROOT; };
FA054611155C465E001F4E37 /* SelectSetVC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = SelectSetVC.mm; path = Bookmarks/SelectSetVC.mm; sourceTree = SOURCE_ROOT; };
FA065FEC128614C400FEA989 /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = SOURCE_ROOT; };
FA09E00F13F71F6C007E69CA /* SearchVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchVC.h; sourceTree = "<group>"; };
FA09E01013F71F6C007E69CA /* SearchVC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchVC.mm; sourceTree = "<group>"; };
FA14064D162A6288002BC1ED /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "empty@2x.png"; path = "Bookmarks/empty@2x.png"; sourceTree = SOURCE_ROOT; };
FA14064E162A6288002BC1ED /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = empty.png; path = Bookmarks/empty.png; sourceTree = SOURCE_ROOT; };
FA14064F162A6288002BC1ED /* eye.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eye.png; path = Bookmarks/eye.png; sourceTree = SOURCE_ROOT; };
@ -1809,8 +1828,6 @@
FA765AB01737BC6D00279CFF /* 44x58-lite.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "44x58-lite.png"; sourceTree = "<group>"; };
FA765AB11737BC6D00279CFF /* 64-lite.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "64-lite.png"; sourceTree = "<group>"; };
FA765AB21737BC6D00279CFF /* 320-lite.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "320-lite.png"; sourceTree = "<group>"; };
FA81AE3114D061BF00A0D70D /* SearchCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchCell.h; sourceTree = "<group>"; };
FA81AE3214D061BF00A0D70D /* SearchCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchCell.mm; sourceTree = "<group>"; };
FA85F632145DDDC20090E1A0 /* packed_polygons.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = packed_polygons.bin; path = ../../data/packed_polygons.bin; sourceTree = SOURCE_ROOT; };
FA87151A12B1518F00592DAF /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
FA8F8937132D5DB00048E3FE /* libtomcrypt.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libtomcrypt.a; sourceTree = SOURCE_ROOT; };
@ -2461,14 +2478,14 @@
97B4E9271851DAB300BEC5D7 /* Custom Views */,
9789DB53188D5DFF007C6FAE /* In App Messaging */,
9770A04618AD19D300126E5C /* More Apps */,
FA4135DF120A25B90062D5B4 /* Settings */,
97A8000918B210DC000C07A2 /* Search */,
978F9251183BD530000D6C7C /* NavigationController.h */,
978F9252183BD530000D6C7C /* NavigationController.mm */,
97D40C0C184E389000A1D572 /* MailComposeViewController.h */,
97D40C0D184E389000A1D572 /* MailComposeViewController.m */,
97387544184E475000170BC4 /* MessageComposeViewController.h */,
97387545184E475000170BC4 /* MessageComposeViewController.m */,
FA09E00F13F71F6C007E69CA /* SearchVC.h */,
FA09E01013F71F6C007E69CA /* SearchVC.mm */,
EE7F297C1219ECA300EB67A9 /* RenderBuffer.hpp */,
EE7F297D1219ECA300EB67A9 /* RenderBuffer.mm */,
EE16192B126E374500622BD0 /* RenderContext.hpp */,
@ -2479,8 +2496,6 @@
1D3623250D0F684500981E51 /* MapsAppDelegate.mm */,
46F8A2EB10EB63040045521A /* MapViewController.h */,
EED10A4411F78D120095FAD4 /* MapViewController.mm */,
FA81AE3114D061BF00A0D70D /* SearchCell.h */,
FA81AE3214D061BF00A0D70D /* SearchCell.mm */,
FAF457E415597BC100DCCC49 /* Framework.h */,
FAF457E615597D4600DCCC49 /* Framework.cpp */,
EDC5C541175F2CA600420E92 /* ShareActionSheet.h */,
@ -2509,7 +2524,6 @@
FA36B8011540388B004560CC /* Bookmarks */,
FA34BEC71338D6DB00FFB2A7 /* Common */,
FA6E1F1B124E6B2800F59149 /* Platform */,
FA4135DF120A25B90062D5B4 /* Settings */,
080E96DDFE201D6D7F000001 /* Classes */,
974726401832306C006B7CB7 /* Categories */,
29B97315FDCFA39411CA2CEA /* Other Sources */,
@ -2659,6 +2673,24 @@
name = Cells;
sourceTree = "<group>";
};
97A8000918B210DC000C07A2 /* Search */ = {
isa = PBXGroup;
children = (
97A8000A18B21363000C07A2 /* SearchView.h */,
97A8000B18B21363000C07A2 /* SearchView.mm */,
97A8000E18B21395000C07A2 /* SearchBar.h */,
97A8000F18B21395000C07A2 /* SearchBar.mm */,
97A8001A18B25497000C07A2 /* SegmentedControl.h */,
97A8001B18B25497000C07A2 /* SegmentedControl.m */,
97A8002518B2741C000C07A2 /* SearchCell.h */,
97A8002618B2741C000C07A2 /* SearchCell.m */,
97A8001218B2140A000C07A2 /* SearchUniversalCell.h */,
97A8001318B2140A000C07A2 /* SearchUniversalCell.m */,
97A8002918B51238000C07A2 /* SearchActivityProtocol.h */,
);
name = Search;
sourceTree = "<group>";
};
97B4E9271851DAB300BEC5D7 /* Custom Views */ = {
isa = PBXGroup;
children = (
@ -3186,6 +3218,7 @@
FA29FDA9141E77F8004ADF66 /* Preferences.mm */,
);
name = Settings;
path = ..;
sourceTree = "<group>";
};
FA6E1F1B124E6B2800F59149 /* Platform */ = {
@ -5047,13 +5080,16 @@
FAFCB63613366E78001A5C59 /* WebViewController.mm in Sources */,
FA34BECA1338D72F00FFB2A7 /* CustomAlertView.mm in Sources */,
97F61781183E6172009919E2 /* LocationButton.mm in Sources */,
FA09E01113F71F6C007E69CA /* SearchVC.mm in Sources */,
9747264318323080006B7CB7 /* UIKitCategories.m in Sources */,
97719D421843AF1E00BDD815 /* ScopeView.m in Sources */,
97A8001418B2140A000C07A2 /* SearchUniversalCell.m in Sources */,
97A8002718B2741C000C07A2 /* SearchCell.m in Sources */,
97D807B818A92AAB00D416E0 /* MoreAppsVC.mm in Sources */,
FABF223E13FAA97A003D4D49 /* CompassView.mm in Sources */,
9789DB5A188D94F9007C6FAE /* InterstitialView.mm in Sources */,
FA29FDAA141E77F8004ADF66 /* Preferences.mm in Sources */,
97A8001C18B25497000C07A2 /* SegmentedControl.m in Sources */,
97A8000C18B21363000C07A2 /* SearchView.mm in Sources */,
FAA5C2A2144F135F005337F6 /* LocationManager.mm in Sources */,
FA81AE3314D061BF00A0D70D /* SearchCell.mm in Sources */,
97DEA09618D75BB000C5F963 /* ContextViews.mm in Sources */,
@ -5079,6 +5115,7 @@
9747277B18328E65006B7CB7 /* SideToolbar.mm in Sources */,
97F61794183E7445009919E2 /* LinkCell.m in Sources */,
EDCB4E8E175E67120005AA35 /* PlacePreviewViewController.mm in Sources */,
97A8001018B21395000C07A2 /* SearchBar.m in Sources */,
EDC5C543175F2CA600420E92 /* ShareActionSheet.mm in Sources */,
EDFC74D0177AE6C500FAF21F /* PlaceAndCompasView.mm in Sources */,
ED48BBB117BE6EA8003E7E92 /* MWMApi.mm in Sources */,
@ -5101,6 +5138,7 @@
97C98643186C487900AF7E9E /* MPInterstitialCustomEvent.m in Sources */,
FAFB08EA151215EE0041901D /* MapsAppDelegate.mm in Sources */,
FAFB08EB151215EE0041901D /* EAGLView.mm in Sources */,
97A8001118B21395000C07A2 /* SearchBar.mm in Sources */,
97C98636186C487900AF7E9E /* MPAnalyticsTracker.m in Sources */,
FAFB08EC151215EE0041901D /* MapViewController.mm in Sources */,
97C98601186C487900AF7E9E /* CJSONSerializedData.m in Sources */,
@ -5126,12 +5164,12 @@
97C9863C186C487900AF7E9E /* MPSessionTracker.m in Sources */,
97C98637186C487900AF7E9E /* MPError.m in Sources */,
97C9863E186C487900AF7E9E /* MPTimer.m in Sources */,
97A8001D18B25497000C07A2 /* SegmentedControl.m in Sources */,
97C9860C186C487900AF7E9E /* MPLegacyBannerCustomEventAdapter.m in Sources */,
FAFB08F2151215EE0041901D /* CustomAlertView.mm in Sources */,
97F61782183E6172009919E2 /* LocationButton.mm in Sources */,
97C9860E186C487900AF7E9E /* MPAdAlertManager.m in Sources */,
97C985F1186C487900AF7E9E /* MPGoogleAdMobBannerCustomEvent.m in Sources */,
FAFB08F3151215EE0041901D /* SearchVC.mm in Sources */,
9747264418323080006B7CB7 /* UIKitCategories.m in Sources */,
97C9863D186C487900AF7E9E /* MPStoreKitProvider.m in Sources */,
97C98600186C487900AF7E9E /* CJSONSerialization.m in Sources */,
@ -5154,13 +5192,13 @@
97C9861F186C487900AF7E9E /* MPInterstitialAdManager.m in Sources */,
97C9862B186C487900AF7E9E /* MRCalendarManager.m in Sources */,
97C98616186C487900AF7E9E /* MPLastResortDelegate.m in Sources */,
FAFB08F8151215EE0041901D /* SearchCell.mm in Sources */,
97C98635186C487900AF7E9E /* UIWebView+MPAdditions.m in Sources */,
97C985F2186C487900AF7E9E /* MPGoogleAdMobInterstitialCustomEvent.m in Sources */,
978F9241183B660F000D6C7C /* SettingsViewController.mm in Sources */,
97C98629186C487900AF7E9E /* MRAdViewDisplayController.m in Sources */,
97C98617186C487900AF7E9E /* MPProgressOverlayView.m in Sources */,
97C98632186C487900AF7E9E /* MRVideoPlayerManager.m in Sources */,
97A8001518B2140A000C07A2 /* SearchUniversalCell.m in Sources */,
97C985F8186C487900AF7E9E /* MPMillennialInterstitialCustomEvent.m in Sources */,
F7B90CD41521E6D200C054EE /* CustomNavigationView.mm in Sources */,
97C98605186C487900AF7E9E /* CJSONScanner.m in Sources */,
@ -5172,6 +5210,7 @@
97C9860F186C487900AF7E9E /* MPAdBrowserController.m in Sources */,
FA5D4F1A1557F79900E7D8BB /* PlacePageVC.mm in Sources */,
FAF457E815597D4600DCCC49 /* Framework.cpp in Sources */,
97A8002818B2741C000C07A2 /* SearchCell.m in Sources */,
97C9860A186C487900AF7E9E /* MPBannerCustomEventAdapter.m in Sources */,
97C98621186C487900AF7E9E /* MPInterstitialViewController.m in Sources */,
FA054613155C465E001F4E37 /* SelectSetVC.mm in Sources */,
@ -5210,6 +5249,7 @@
EDFC74D1177AE6C500FAF21F /* PlaceAndCompasView.mm in Sources */,
ED48BBB217BE6EA8003E7E92 /* MWMApi.mm in Sources */,
97C9862F186C487900AF7E9E /* MRJavaScriptEventEmitter.m in Sources */,
97A8000D18B21363000C07A2 /* SearchView.mm in Sources */,
97C98628186C487900AF7E9E /* MRAdView.m in Sources */,
97C9862A186C487900AF7E9E /* MRBundleManager.m in Sources */,
ED48BBBB17C2B1E2003E7E92 /* CircleView.mm in Sources */,