[ios] Redesign and refactor main Search screen UI #10213
55 changed files with 2207 additions and 1955 deletions
|
@ -1,11 +1,11 @@
|
|||
#import "MWMBottomMenuState.h"
|
||||
#import "MWMMapDownloaderMode.h"
|
||||
#import "MWMNavigationDashboardManager.h"
|
||||
#import "MWMSearchManager.h"
|
||||
|
||||
@class MapViewController;
|
||||
@class BottomTabBarViewController;
|
||||
@class TrackRecordingViewController;
|
||||
|
||||
@protocol MWMFeatureHolder;
|
||||
|
||||
@interface MWMMapViewControlsManager : NSObject
|
||||
|
@ -47,7 +47,6 @@
|
|||
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode;
|
||||
- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale;
|
||||
- (void)searchTextOnMap:(NSString *)text forInputLocale:(NSString *)locale;
|
||||
- (void)hideSearch;
|
||||
|
||||
#pragma mark - MWMFeatureHolder
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#import "MWMNetworkPolicy+UI.h"
|
||||
#import "MWMPlacePageManager.h"
|
||||
#import "MWMPlacePageProtocol.h"
|
||||
#import "MWMSearchManager.h"
|
||||
#import "MWMSideButtons.h"
|
||||
#import "MWMTrafficButtonViewController.h"
|
||||
#import "MWMMapWidgetsHelper.h"
|
||||
|
@ -27,8 +26,7 @@ namespace {
|
|||
NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
||||
} // namespace
|
||||
|
||||
@interface MWMMapViewControlsManager () <BottomMenuDelegate,
|
||||
MWMSearchManagerObserver>
|
||||
@interface MWMMapViewControlsManager () <BottomMenuDelegate>
|
||||
|
||||
@property(nonatomic) MWMSideButtons *sideButtons;
|
||||
@property(nonatomic) MWMTrafficButtonViewController *trafficButton;
|
||||
|
@ -36,7 +34,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
@property(nonatomic) UIViewController *menuController;
|
||||
@property(nonatomic) id<MWMPlacePageProtocol> placePageManager;
|
||||
@property(nonatomic) MWMNavigationDashboardManager *navigationManager;
|
||||
@property(nonatomic) MWMSearchManager *searchManager;
|
||||
@property(nonatomic) SearchOnMapManager *searchManager;
|
||||
|
||||
@property(weak, nonatomic) MapViewController *ownerController;
|
||||
|
||||
|
@ -50,6 +48,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
+ (MWMMapViewControlsManager *)manager {
|
||||
return [MapViewController sharedController].controlsManager;
|
||||
}
|
||||
|
||||
- (instancetype)initWithParentController:(MapViewController *)controller {
|
||||
if (!controller)
|
||||
return nil;
|
||||
|
@ -67,6 +66,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
[TrackRecordingManager.shared addObserver:self recordingIsActiveDidChangeHandler:^(TrackRecordingState state, TrackInfo * trackInfo) {
|
||||
[self setTrackRecordingButtonHidden:state == TrackRecordingStateInactive];
|
||||
}];
|
||||
self.searchManager = controller.searchManager;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
BOOL const isSearchUnderStatusBar = (self.searchManager.state != MWMSearchManagerStateHidden);
|
||||
BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden &&
|
||||
self.navigationManager.state != MWMNavigationDashboardStateNavigation;
|
||||
BOOL const isMenuViewUnderStatusBar = self.menuState == MWMBottomMenuStateActive;
|
||||
|
@ -83,7 +82,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
BOOL const isAddPlaceUnderStatusBar =
|
||||
[self.ownerController.view hasSubviewWithViewClass:[MWMAddPlaceNavigationBar class]];
|
||||
BOOL const isNightMode = [UIColor isNightMode];
|
||||
BOOL const isSomethingUnderStatusBar = isSearchUnderStatusBar || isNavigationUnderStatusBar ||
|
||||
BOOL const isSomethingUnderStatusBar = isNavigationUnderStatusBar ||
|
||||
isDirectionViewUnderStatusBar || isMenuViewUnderStatusBar ||
|
||||
isAddPlaceUnderStatusBar;
|
||||
|
||||
|
@ -101,7 +100,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
[self.trafficButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.trackRecordingButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.tabBarController viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.searchManager viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
|
||||
#pragma mark - MWMPlacePageViewManager
|
||||
|
@ -110,24 +108,19 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
if (![self searchText:text forInputLocale:locale])
|
||||
return;
|
||||
|
||||
self.searchManager.state = MWMSearchManagerStateMapSearch;
|
||||
[self.searchManager startSearchingWithIsRouting:NO];
|
||||
}
|
||||
|
||||
- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale {
|
||||
if (text.length == 0)
|
||||
return NO;
|
||||
|
||||
self.searchManager.state = MWMSearchManagerStateTableSearch;
|
||||
[self.searchManager searchText:text forInputLocale:locale withCategory:NO];
|
||||
[self.searchManager startSearchingWithIsRouting:NO];
|
||||
[self.searchManager searchText:text locale:locale isCategory:NO];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)hideSearch {
|
||||
self.searchManager.state = MWMSearchManagerStateHidden;
|
||||
}
|
||||
|
||||
#pragma mark - BottomMenuDelegate
|
||||
|
||||
#pragma mark - BottomMenu
|
||||
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode {
|
||||
[self.ownerController openMapsDownloader:mode];
|
||||
}
|
||||
|
@ -146,7 +139,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
MapViewController *ownerController = self.ownerController;
|
||||
|
||||
self.isAddingPlace = YES;
|
||||
self.searchManager.state = MWMSearchManagerStateHidden;
|
||||
[self.searchManager close];
|
||||
self.menuState = MWMBottomMenuStateHidden;
|
||||
self.trafficButtonHidden = YES;
|
||||
|
||||
|
@ -181,15 +174,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
[[MapsAppDelegate theApp] enableStandby];
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchManagerObserver
|
||||
|
||||
- (void)onSearchManagerStateChanged {
|
||||
auto state = [MWMSearchManager manager].state;
|
||||
if (!IPAD && state == MWMSearchManagerStateHidden) {
|
||||
self.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Routing
|
||||
|
||||
- (void)onRoutePrepare {
|
||||
|
@ -201,16 +185,12 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
}
|
||||
|
||||
- (void)onRouteRebuild {
|
||||
if (IPAD)
|
||||
self.searchManager.state = MWMSearchManagerStateHidden;
|
||||
|
||||
[self.ownerController.bookmarksCoordinator close];
|
||||
[self.navigationManager onRoutePlanning];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)onRouteReady:(BOOL)hasWarnings {
|
||||
self.searchManager.state = MWMSearchManagerStateHidden;
|
||||
[self.navigationManager onRouteReady:hasWarnings];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
@ -226,7 +206,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
}
|
||||
|
||||
- (void)onRouteStop {
|
||||
self.searchManager.state = MWMSearchManagerStateHidden;
|
||||
self.sideButtons.zoomHidden = self.zoomHidden;
|
||||
[self.navigationManager onRouteStop];
|
||||
self.disableStandbyOnRouteFollowing = NO;
|
||||
|
@ -236,17 +215,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
|
||||
#pragma mark - Properties
|
||||
|
||||
/*
|
||||
- (UIButton *)promoButton {
|
||||
if (!_promoButton) {
|
||||
PromoCoordinator *coordinator = [[PromoCoordinator alloc] initWithViewController:self.ownerController
|
||||
campaign:_promoDiscoveryCampaign];
|
||||
_promoButton = [[PromoButton alloc] initWithCoordinator:coordinator];
|
||||
}
|
||||
return _promoButton;
|
||||
}
|
||||
*/
|
||||
|
||||
- (MWMSideButtons *)sideButtons {
|
||||
if (!_sideButtons)
|
||||
_sideButtons = [[MWMSideButtons alloc] initWithParentView:self.ownerController.controlsView];
|
||||
|
@ -283,14 +251,6 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
return _navigationManager;
|
||||
}
|
||||
|
||||
- (MWMSearchManager *)searchManager {
|
||||
if (!_searchManager) {
|
||||
_searchManager = [[MWMSearchManager alloc] init];
|
||||
[MWMSearchManager addObserver:self];
|
||||
}
|
||||
return _searchManager;
|
||||
}
|
||||
|
||||
@synthesize menuState = _menuState;
|
||||
|
||||
- (void)setHidden:(BOOL)hidden {
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
- (void)processMyPositionStateModeEvent:(MWMMyPositionMode)mode;
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame;
|
||||
+ (CGRect)getAvailableArea;
|
||||
|
||||
@end
|
||||
|
|
|
@ -57,6 +57,9 @@ NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapTo
|
|||
}
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame { [[self buttons].sideView updateAvailableArea:frame]; }
|
||||
|
||||
+ (CGRect)getAvailableArea { return [self buttons].sideView.getAvailableArea; }
|
||||
|
||||
- (void)zoomIn
|
||||
{
|
||||
GetFramework().Scale(Framework::SCALE_MAG, true);
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated;
|
||||
|
||||
- (void)updateAvailableArea:(CGRect)frame;
|
||||
- (CGRect)getAvailableArea;
|
||||
|
||||
@end
|
||||
|
|
|
@ -144,6 +144,10 @@ CGFloat const kButtonsBottomOffset = 6;
|
|||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CGRect)getAvailableArea {
|
||||
return self.availableArea;
|
||||
}
|
||||
|
||||
- (CGFloat)availableHeight {
|
||||
return self.availableArea.size.height - kButtonsTopOffset - kButtonsBottomOffset;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
|
|||
|
||||
@end
|
||||
|
||||
@interface MWMNavigationDashboardManager () <MWMSearchManagerObserver, MWMRoutePreviewDelegate>
|
||||
@interface MWMNavigationDashboardManager () <SearchOnMapManagerObserver, MWMRoutePreviewDelegate>
|
||||
|
||||
@property(copy, nonatomic) NSDictionary *etaAttributes;
|
||||
@property(copy, nonatomic) NSDictionary *etaSecondaryAttributes;
|
||||
|
@ -52,6 +52,10 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
|
|||
return self;
|
||||
}
|
||||
|
||||
- (SearchOnMapManager *)searchManager {
|
||||
return [[MapViewController sharedController] searchManager];
|
||||
}
|
||||
|
||||
- (void)loadPreviewWithStatusBoxes {
|
||||
[NSBundle.mainBundle loadNibNamed:kRoutePreviewIPhoneXibName owner:self options:nil];
|
||||
auto ownerView = self.ownerView;
|
||||
|
@ -238,14 +242,20 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
|
|||
- (IBAction)stopRoutingButtonAction {
|
||||
[MWMSearch clear];
|
||||
[MWMRouter stopRouting];
|
||||
[self.searchManager close];
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchManagerObserver
|
||||
#pragma mark - SearchOnMapManagerObserver
|
||||
|
||||
- (void)onSearchManagerStateChanged {
|
||||
auto state = [MWMSearchManager manager].state;
|
||||
if (state == MWMSearchManagerStateMapSearch)
|
||||
[self setMapSearch];
|
||||
- (void)searchManagerWithDidChangeState:(SearchOnMapState)state {
|
||||
switch (state) {
|
||||
case SearchOnMapStateClosed:
|
||||
[self.navigationInfoView setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
|
||||
break;
|
||||
case SearchOnMapStateHidden:
|
||||
case SearchOnMapStateSearching:
|
||||
[self setMapSearch];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Available area
|
||||
|
@ -261,9 +271,9 @@ NSString *const kNavigationControlViewXibName = @"NavigationControlView";
|
|||
|
||||
- (void)setState:(MWMNavigationDashboardState)state {
|
||||
if (state == MWMNavigationDashboardStateHidden)
|
||||
[MWMSearchManager removeObserver:self];
|
||||
[self.searchManager removeObserver:self];
|
||||
else
|
||||
[MWMSearchManager addObserver:self];
|
||||
[self.searchManager addObserver:self];
|
||||
switch (state) {
|
||||
case MWMNavigationDashboardStateHidden:
|
||||
[self stateHidden];
|
||||
|
|
|
@ -25,6 +25,8 @@ typedef NS_ENUM(NSUInteger, MWMNavigationInfoViewState) {
|
|||
@property(weak, nonatomic) UIView * ownerView;
|
||||
@property(nonatomic) CGRect availableArea;
|
||||
|
||||
- (void)setSearchState:(NavigationSearchState)searchState animated:(BOOL)animated;
|
||||
|
||||
- (void)onNavigationInfoUpdated:(MWMNavigationDashboardEntity *)info;
|
||||
|
||||
- (void)setMapSearch;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#import "MWMLocationObserver.h"
|
||||
#import "MWMMapViewControlsCommon.h"
|
||||
#import "MWMSearch.h"
|
||||
#import "MWMSearchManager.h"
|
||||
#import "MapViewController.h"
|
||||
#import "SwiftBridge.h"
|
||||
#import "UIImageView+Coloring.h"
|
||||
|
@ -143,13 +142,16 @@ BOOL defaultOrientation(CGSize const &size) {
|
|||
[toastView configWithIsStart:YES withLocationButton:NO];
|
||||
}
|
||||
|
||||
- (SearchOnMapManager *)searchManager {
|
||||
return [MapViewController sharedController].searchManager;
|
||||
}
|
||||
|
||||
- (IBAction)openSearch {
|
||||
BOOL const isStart = self.toastView.isStart;
|
||||
auto searchManager = [MWMSearchManager manager];
|
||||
|
||||
searchManager.routingTooltipSearch =
|
||||
isStart ? MWMSearchManagerRoutingTooltipSearchStart : MWMSearchManagerRoutingTooltipSearchFinish;
|
||||
searchManager.state = MWMSearchManagerStateDefault;
|
||||
[self.searchManager setRoutingTooltip:
|
||||
isStart ? SearchOnMapRoutingTooltipSearchStart : SearchOnMapRoutingTooltipSearchFinish ];
|
||||
[self.searchManager startSearchingWithIsRouting:YES];
|
||||
}
|
||||
|
||||
- (IBAction)addLocationRoutePoint {
|
||||
|
@ -166,12 +168,12 @@ BOOL defaultOrientation(CGSize const &size) {
|
|||
- (IBAction)searchMainButtonTouchUpInside {
|
||||
switch (self.searchState) {
|
||||
case NavigationSearchState::Maximized:
|
||||
[MWMSearchManager manager].state = MWMSearchManagerStateDefault;
|
||||
[self.searchManager startSearchingWithIsRouting:YES];
|
||||
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
|
||||
break;
|
||||
case NavigationSearchState::MinimizedNormal:
|
||||
if (self.state == MWMNavigationInfoViewStatePrepare) {
|
||||
[MWMSearchManager manager].state = MWMSearchManagerStateDefault;
|
||||
[self.searchManager startSearchingWithIsRouting:YES];
|
||||
} else {
|
||||
[self setSearchState:NavigationSearchState::Maximized animated:YES];
|
||||
}
|
||||
|
@ -183,7 +185,7 @@ BOOL defaultOrientation(CGSize const &size) {
|
|||
case NavigationSearchState::MinimizedFood:
|
||||
case NavigationSearchState::MinimizedATM:
|
||||
[MWMSearch clear];
|
||||
[MWMSearchManager manager].state = MWMSearchManagerStateHidden;
|
||||
[self.searchManager hide];
|
||||
[self setSearchState:NavigationSearchState::MinimizedNormal animated:YES];
|
||||
break;
|
||||
}
|
||||
|
@ -191,7 +193,6 @@ BOOL defaultOrientation(CGSize const &size) {
|
|||
|
||||
- (IBAction)searchButtonTouchUpInside:(MWMButton *)sender {
|
||||
auto const body = ^(NavigationSearchState state) {
|
||||
[MWMSearch setSearchOnMap:YES];
|
||||
NSString *query = [kSearchButtonRequest.at(state) stringByAppendingString:@" "];
|
||||
NSString *locale = [[AppInfo sharedInfo] languageId];
|
||||
// Category request from navigation search wheel.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@class EAGLView;
|
||||
@class MWMMapDownloadDialog;
|
||||
@class BookmarksCoordinator;
|
||||
@class SearchOnMapManager;
|
||||
@protocol MWMLocationModeListener;
|
||||
|
||||
@interface MapViewController : MWMViewController
|
||||
|
@ -46,11 +47,10 @@
|
|||
@property(nonatomic, readonly) MWMMapViewControlsManager * _Nonnull controlsManager;
|
||||
@property(nonatomic, readonly) MWMMapDownloadDialog * _Nonnull downloadDialog;
|
||||
@property(nonatomic, readonly) BookmarksCoordinator * _Nonnull bookmarksCoordinator;
|
||||
@property(nonatomic, readonly) SearchOnMapManager * _Nonnull searchManager;
|
||||
|
||||
@property(nonatomic) MWMMyPositionMode currentPositionMode;
|
||||
@property(strong, nonatomic) IBOutlet EAGLView * _Nonnull mapView;
|
||||
@property(strong, nonatomic) IBOutlet UIView * _Nonnull controlsView;
|
||||
@property(strong, nonatomic) IBOutlet UIView * _Nonnull searchViewContainer;
|
||||
@property(strong, nonatomic) IBOutlet NSLayoutConstraint * _Nonnull searchViewContainerLeadingConstraint;
|
||||
|
||||
@end
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
extern NSString *const kMap2FBLoginSegue = @"Map2FBLogin";
|
||||
extern NSString *const kMap2GoogleLoginSegue = @"Map2GoogleLogin";
|
||||
|
||||
static CGFloat kPlacePageCompactWidth = 350;
|
||||
static CGFloat kPlacePageLeadingOffset = IPAD ? 20 : 0;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, UserTouchesAction) { UserTouchesActionNone, UserTouchesActionDrag, UserTouchesActionScale };
|
||||
|
||||
namespace {
|
||||
|
@ -72,6 +75,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
UIGestureRecognizerDelegate>
|
||||
|
||||
@property(nonatomic, readwrite) MWMMapViewControlsManager *controlsManager;
|
||||
@property(nonatomic, readwrite) SearchOnMapManager *searchManager;
|
||||
|
||||
@property(nonatomic) BOOL disableStandbyOnLocationStateMode;
|
||||
|
||||
|
@ -97,7 +101,11 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
@property(nonatomic) BOOL needDeferFocusNotification;
|
||||
@property(nonatomic) BOOL deferredFocusValue;
|
||||
@property(nonatomic) PlacePageViewController *placePageVC;
|
||||
@property(nonatomic) IBOutlet UIView *placePageContainer;
|
||||
@property(nonatomic) UIView *placePageContainer;
|
||||
|
||||
@property(nonatomic) NSLayoutConstraint *placePageWidthConstraint;
|
||||
@property(nonatomic) NSLayoutConstraint *placePageLeadingConstraint;
|
||||
@property(nonatomic) NSLayoutConstraint *placePageTrailingConstraint;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -111,6 +119,9 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
#pragma mark - Map Navigation
|
||||
|
||||
- (void)showOrUpdatePlacePage:(PlacePageData *)data {
|
||||
if (self.searchManager.isSearching)
|
||||
[self.searchManager setPlaceOnMapSelected:YES];
|
||||
|
||||
self.controlsManager.trafficButtonHidden = YES;
|
||||
if (self.placePageVC != nil) {
|
||||
[PlacePageBuilder update:(PlacePageViewController *)self.placePageVC with:data];
|
||||
|
@ -120,19 +131,58 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
}
|
||||
|
||||
- (void)showPlacePageFor:(PlacePageData *)data {
|
||||
self.placePageVC = [PlacePageBuilder buildFor:data];
|
||||
self.placePageContainer.hidden = NO;
|
||||
self.placePageVC.view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
self.placePageVC = [PlacePageBuilder buildFor:data];
|
||||
[self.placePageContainer addSubview:self.placePageVC.view];
|
||||
[self.view bringSubviewToFront:self.placePageContainer];
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[self.placePageVC.view.topAnchor constraintEqualToAnchor:self.placePageContainer.safeAreaLayoutGuide.topAnchor],
|
||||
[self.placePageVC.view.leftAnchor constraintEqualToAnchor:self.placePageContainer.leftAnchor],
|
||||
[self.placePageVC.view.bottomAnchor constraintEqualToAnchor:self.placePageContainer.bottomAnchor],
|
||||
[self.placePageVC.view.rightAnchor constraintEqualToAnchor:self.placePageContainer.rightAnchor]
|
||||
]];
|
||||
[self addChildViewController:self.placePageVC];
|
||||
[self.placePageVC didMoveToParentViewController:self];
|
||||
self.placePageVC.view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[self.placePageVC.view.topAnchor constraintEqualToAnchor:self.placePageContainer.topAnchor],
|
||||
[self.placePageVC.view.leadingAnchor constraintEqualToAnchor:self.placePageContainer.leadingAnchor],
|
||||
[self.placePageVC.view.bottomAnchor constraintEqualToAnchor:self.placePageContainer.bottomAnchor],
|
||||
[self.placePageVC.view.trailingAnchor constraintEqualToAnchor:self.placePageContainer.trailingAnchor]
|
||||
]];
|
||||
[self updatePlacePageContainerConstraints];
|
||||
}
|
||||
|
||||
- (void)setupPlacePageContainer {
|
||||
self.placePageContainer = [[TouchTransparentView alloc] initWithFrame:self.view.bounds];
|
||||
[self.view addSubview:self.placePageContainer];
|
||||
[self.view bringSubviewToFront:self.placePageContainer];
|
||||
|
||||
self.placePageContainer.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
self.placePageLeadingConstraint = [self.placePageContainer.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor constant:kPlacePageLeadingOffset];
|
||||
self.placePageLeadingConstraint.active = YES;
|
||||
|
||||
self.placePageWidthConstraint = [self.placePageContainer.widthAnchor constraintEqualToConstant:0];
|
||||
self.placePageTrailingConstraint = [self.placePageContainer.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor];
|
||||
|
||||
[self.placePageContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
|
||||
if (IPAD) {
|
||||
self.placePageLeadingConstraint.priority = UILayoutPriorityDefaultLow;
|
||||
[self.placePageContainer.bottomAnchor constraintLessThanOrEqualToAnchor:self.view.bottomAnchor].active = YES;
|
||||
}
|
||||
else {
|
||||
[self.placePageContainer.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
|
||||
}
|
||||
|
||||
[self updatePlacePageContainerConstraints];
|
||||
}
|
||||
|
||||
- (void)updatePlacePageContainerConstraints {
|
||||
const BOOL isLimitedWidth = IPAD || self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact;
|
||||
[self.placePageWidthConstraint setConstant:kPlacePageCompactWidth];
|
||||
|
||||
if (IPAD && self.searchViewContainer != nil) {
|
||||
NSLayoutConstraint * leadingToSearchConstraint = [self.placePageContainer.leadingAnchor constraintEqualToAnchor:self.searchViewContainer.trailingAnchor constant:kPlacePageLeadingOffset];
|
||||
leadingToSearchConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||
leadingToSearchConstraint.active = isLimitedWidth;
|
||||
}
|
||||
|
||||
[self.placePageWidthConstraint setActive:isLimitedWidth];
|
||||
[self.placePageTrailingConstraint setActive:!isLimitedWidth];
|
||||
[self.view layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)dismissPlacePage {
|
||||
|
@ -160,16 +210,10 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
- (void)onMapObjectDeselected {
|
||||
[self hidePlacePage];
|
||||
|
||||
MWMSearchManager * searchManager = MWMSearchManager.manager;
|
||||
BOOL const isSearchResult = searchManager.state == MWMSearchManagerStateResult;
|
||||
BOOL const isSearching = self.searchManager.isSearching;
|
||||
BOOL const isNavigationDashboardHidden = [MWMNavigationDashboardManager sharedManager].state == MWMNavigationDashboardStateHidden;
|
||||
if (isSearchResult) {
|
||||
if (isNavigationDashboardHidden) {
|
||||
searchManager.state = MWMSearchManagerStateMapSearch;
|
||||
} else {
|
||||
searchManager.state = MWMSearchManagerStateHidden;
|
||||
}
|
||||
}
|
||||
if (isSearching)
|
||||
[self.searchManager setPlaceOnMapSelected:!isNavigationDashboardHidden];
|
||||
// Always show the controls during the navigation or planning mode.
|
||||
if (!isNavigationDashboardHidden)
|
||||
self.controlsManager.hidden = NO;
|
||||
|
@ -177,8 +221,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
|
||||
- (void)onSwitchFullScreen {
|
||||
BOOL const isNavigationDashboardHidden = MWMNavigationDashboardManager.sharedManager.state == MWMNavigationDashboardStateHidden;
|
||||
BOOL const isSearchHidden = MWMSearchManager.manager.state == MWMSearchManagerStateHidden;
|
||||
if (isSearchHidden && isNavigationDashboardHidden) {
|
||||
if (!self.searchManager.isSearching && isNavigationDashboardHidden) {
|
||||
if (!self.controlsManager.hidden)
|
||||
[self dismissPlacePage];
|
||||
self.controlsManager.hidden = !self.controlsManager.hidden;
|
||||
|
@ -215,6 +258,10 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
if ([MWMCarPlayService shared].isCarplayActivated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.searchManager.isSearching && type == df::TouchEvent::TOUCH_MOVE)
|
||||
[self.searchManager setMapIsDragging];
|
||||
|
||||
NSArray *allTouches = [[event allTouches] allObjects];
|
||||
if ([allTouches count] < 1)
|
||||
return;
|
||||
|
@ -287,6 +334,12 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
[self.controlsManager viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
if (self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass)
|
||||
[self updatePlacePageContainerConstraints];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
GetFramework().MemoryWarning();
|
||||
[super didReceiveMemoryWarning];
|
||||
|
@ -305,8 +358,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
if ([MWMNavigationDashboardManager sharedManager].state == MWMNavigationDashboardStateHidden &&
|
||||
[MWMSearchManager manager].state == MWMSearchManagerStateHidden)
|
||||
if ([MWMNavigationDashboardManager sharedManager].state == MWMNavigationDashboardStateHidden)
|
||||
self.controlsManager.menuState = self.controlsManager.menuRestoreState;
|
||||
|
||||
[self updateStatusBarStyle];
|
||||
|
@ -319,6 +371,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self setupPlacePageContainer];
|
||||
|
||||
if (@available(iOS 14.0, *))
|
||||
[self setupTrackPadGestureRecognizers];
|
||||
|
@ -441,8 +494,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
if ([MWMNavigationDashboardManager sharedManager].state == MWMNavigationDashboardStateHidden &&
|
||||
[MWMSearchManager manager].state == MWMSearchManagerStateHidden)
|
||||
if ([MWMNavigationDashboardManager sharedManager].state == MWMNavigationDashboardStateHidden)
|
||||
self.controlsManager.menuRestoreState = self.controlsManager.menuState;
|
||||
GetFramework().SetRenderingDisabled(false);
|
||||
}
|
||||
|
@ -605,15 +657,13 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
- (void)performAction:(NSString *)action {
|
||||
[self.navigationController popToRootViewControllerAnimated:NO];
|
||||
if (self.isViewLoaded) {
|
||||
auto searchState = MWMSearchManagerStateHidden;
|
||||
[MWMRouter stopRouting];
|
||||
if ([action isEqualToString:@"app.organicmaps.3daction.bookmarks"])
|
||||
[self.bookmarksCoordinator open];
|
||||
else if ([action isEqualToString:@"app.organicmaps.3daction.search"])
|
||||
searchState = MWMSearchManagerStateDefault;
|
||||
[self.searchManager startSearchingWithIsRouting:NO];
|
||||
else if ([action isEqualToString:@"app.organicmaps.3daction.route"])
|
||||
[self.controlsManager onRoutePrepare];
|
||||
[MWMSearchManager manager].state = searchState;
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self performAction:action];
|
||||
|
@ -674,9 +724,20 @@ NSString *const kSettingsSegue = @"Map2Settings";
|
|||
return _controlsManager;
|
||||
}
|
||||
|
||||
- (SearchOnMapManager *)searchManager {
|
||||
if (!_searchManager)
|
||||
_searchManager = [[SearchOnMapManager alloc] initWithNavigationController:self.navigationController];
|
||||
return _searchManager;
|
||||
}
|
||||
|
||||
- (UIView * _Nullable)searchViewContainer {
|
||||
return self.searchManager.viewController.view;
|
||||
}
|
||||
|
||||
- (BOOL)hasNavigationBar {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (MWMMapDownloadDialog *)downloadDialog {
|
||||
if (!_downloadDialog)
|
||||
_downloadDialog = [MWMMapDownloadDialog dialogForController:self];
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import Foundation
|
||||
|
||||
private func IPAD() -> Bool { return UI_USER_INTERFACE_IDIOM() == .pad }
|
||||
var isIPad: Bool { return UI_USER_INTERFACE_IDIOM() == .pad }
|
||||
|
||||
func L(_ key: String) -> String { return NSLocalizedString(key, comment: "") }
|
||||
|
||||
func alternative<T>(iPhone: T, iPad: T) -> T { return IPAD() ? iPad : iPhone }
|
||||
func alternative<T>(iPhone: T, iPad: T) -> T { return isIPad ? iPad : iPhone }
|
||||
|
||||
func iPadSpecific(_ f: () -> Void) {
|
||||
if IPAD() {
|
||||
if isIPad {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
func iPhoneSpecific(_ f: () -> Void) {
|
||||
if !IPAD() {
|
||||
if !isIPad {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class SearchResult;
|
||||
|
||||
NS_SWIFT_NAME(Search)
|
||||
@interface MWMSearch : NSObject
|
||||
|
||||
@protocol SearchManager
|
||||
+ (void)addObserver:(id<MWMSearchObserver>)observer;
|
||||
+ (void)removeObserver:(id<MWMSearchObserver>)observer;
|
||||
|
||||
|
@ -15,15 +13,21 @@ NS_SWIFT_NAME(Search)
|
|||
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory;
|
||||
|
||||
+ (void)showResultAtIndex:(NSUInteger)index;
|
||||
+ (void)showEverywhereSearchResultsOnMap;
|
||||
+ (void)showViewportSearchResultsOnMap;
|
||||
|
||||
+ (NSArray<SearchResult *> *)getResults;
|
||||
|
||||
+ (void)clear;
|
||||
@end
|
||||
|
||||
NS_SWIFT_NAME(Search)
|
||||
@interface MWMSearch : NSObject<SearchManager>
|
||||
|
||||
+ (SearchItemType)resultTypeWithRow:(NSUInteger)row;
|
||||
+ (NSUInteger)containerIndexWithRow:(NSUInteger)row;
|
||||
+ (SearchResult *)resultWithContainerIndex:(NSUInteger)index;
|
||||
|
||||
+ (void)clear;
|
||||
|
||||
+ (void)setSearchOnMap:(BOOL)searchOnMap;
|
||||
|
||||
+ (NSUInteger)suggestionsCount;
|
||||
+ (NSUInteger)resultsCount;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ using Observers = NSHashTable<Observer>;
|
|||
@interface MWMSearch () <MWMFrameworkDrapeObserver>
|
||||
|
||||
@property(nonatomic) NSUInteger suggestionsCount;
|
||||
@property(nonatomic) BOOL searchOnMap;
|
||||
|
||||
@property(nonatomic) BOOL textChanged;
|
||||
|
||||
|
@ -111,16 +110,8 @@ using Observers = NSHashTable<Observer>;
|
|||
[self reset];
|
||||
if (m_query.empty())
|
||||
return;
|
||||
|
||||
if (IPAD) {
|
||||
[self searchInViewport];
|
||||
[self searchEverywhere];
|
||||
} else {
|
||||
if (self.searchOnMap)
|
||||
[self searchInViewport];
|
||||
else
|
||||
[self searchEverywhere];
|
||||
}
|
||||
[self searchInViewport];
|
||||
[self searchEverywhere];
|
||||
}
|
||||
|
||||
#pragma mark - Add/Remove Observers
|
||||
|
@ -165,7 +156,7 @@ using Observers = NSHashTable<Observer>;
|
|||
|
||||
+ (void)showResultAtIndex:(NSUInteger)index {
|
||||
auto const & result = [MWMSearch manager]->m_everywhereResults[index];
|
||||
GetFramework().ShowSearchResult(result);
|
||||
GetFramework().SelectSearchResult(result, true);
|
||||
}
|
||||
|
||||
+ (SearchResult *)resultWithContainerIndex:(NSUInteger)index {
|
||||
|
@ -175,6 +166,27 @@ using Observers = NSHashTable<Observer>;
|
|||
return result;
|
||||
}
|
||||
|
||||
+ (void)showEverywhereSearchResultsOnMap {
|
||||
MWMSearch * manager = [MWMSearch manager];
|
||||
if (![MWMRouter isRoutingActive])
|
||||
GetFramework().ShowSearchResults(manager->m_everywhereResults);
|
||||
}
|
||||
|
||||
+ (void)showViewportSearchResultsOnMap {
|
||||
MWMSearch * manager = [MWMSearch manager];
|
||||
if (![MWMRouter isRoutingActive])
|
||||
[manager processViewportChangedEvent];
|
||||
}
|
||||
|
||||
+ (NSArray<SearchResult *> *)getResults {
|
||||
NSMutableArray<SearchResult *> * results = [[NSMutableArray alloc] initWithCapacity:MWMSearch.resultsCount];
|
||||
for (NSUInteger i = 0; i < MWMSearch.resultsCount; ++i) {
|
||||
SearchResult * result = [MWMSearch resultWithContainerIndex:i];
|
||||
[results addObject:result];
|
||||
}
|
||||
return [results copy];
|
||||
}
|
||||
|
||||
+ (SearchItemType)resultTypeWithRow:(NSUInteger)row {
|
||||
auto itemsIndex = [MWMSearch manager].itemsIndex;
|
||||
return [itemsIndex resultTypeWithRow:row];
|
||||
|
@ -202,18 +214,6 @@ using Observers = NSHashTable<Observer>;
|
|||
[manager reset];
|
||||
}
|
||||
|
||||
+ (void)setSearchOnMap:(BOOL)searchOnMap {
|
||||
if (IPAD)
|
||||
return;
|
||||
MWMSearch *manager = [MWMSearch manager];
|
||||
if (manager.searchOnMap == searchOnMap)
|
||||
return;
|
||||
manager.searchOnMap = searchOnMap;
|
||||
if (searchOnMap && ![MWMRouter isRoutingActive])
|
||||
GetFramework().ShowSearchResults(manager->m_everywhereResults);
|
||||
[manager update];
|
||||
}
|
||||
|
||||
+ (NSUInteger)suggestionsCount {
|
||||
return [MWMSearch manager].suggestionsCount;
|
||||
}
|
||||
|
@ -259,8 +259,7 @@ using Observers = NSHashTable<Observer>;
|
|||
- (void)processViewportChangedEvent {
|
||||
if (!GetFramework().GetSearchAPI().IsViewportSearchActive())
|
||||
return;
|
||||
if (IPAD)
|
||||
[self searchEverywhere];
|
||||
[self searchEverywhere];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
enum SearchStyleSheet: String, CaseIterable {
|
||||
case searchHeader
|
||||
case searchInstallButton = "SearchInstallButton"
|
||||
case searchBanner = "SearchBanner"
|
||||
case searchClosedBackground = "SearchClosedBackground"
|
||||
|
@ -16,6 +17,17 @@ enum SearchStyleSheet: String, CaseIterable {
|
|||
extension SearchStyleSheet: IStyleSheet {
|
||||
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
|
||||
switch self {
|
||||
case .searchHeader:
|
||||
return .add { s in
|
||||
s.backgroundColor = colors.primary
|
||||
iPhoneSpecific {
|
||||
s.shadowColor = UIColor.black
|
||||
s.shadowOffset = CGSize(width: 0, height: 1)
|
||||
s.shadowOpacity = 0.5
|
||||
s.shadowRadius = 3
|
||||
s.cornerRadius = 10
|
||||
}
|
||||
}
|
||||
case .searchInstallButton:
|
||||
return .add { s in
|
||||
s.cornerRadius = 10
|
||||
|
|
|
@ -86,7 +86,6 @@
|
|||
3490D2E31CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3490D2DD1CE9DD2500D0B838 /* MWMSideButtonsView.xib */; };
|
||||
349A13831DEC138C00C7DB60 /* MWMMobileInternetAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 349A13801DEC138C00C7DB60 /* MWMMobileInternetAlert.m */; };
|
||||
349A13851DEC138C00C7DB60 /* MWMMobileInternetAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = 349A13811DEC138C00C7DB60 /* MWMMobileInternetAlert.xib */; };
|
||||
349D1ABC1E2D05EF004A2006 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349D1ABA1E2D05EF004A2006 /* SearchBar.swift */; };
|
||||
349D1AD51E2E325B004A2006 /* BottomMenuItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 349D1AC61E2E325B004A2006 /* BottomMenuItemCell.xib */; };
|
||||
349D1AE11E2E325C004A2006 /* BottomTabBarViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 349D1ACD1E2E325B004A2006 /* BottomTabBarViewController.xib */; };
|
||||
349D1CE41E3F836900A878FD /* UIViewController+Hierarchy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349D1CE21E3F836900A878FD /* UIViewController+Hierarchy.swift */; };
|
||||
|
@ -334,7 +333,6 @@
|
|||
99012852244732DB00C72B10 /* BottomTabBarBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9901284C244732DB00C72B10 /* BottomTabBarBuilder.swift */; };
|
||||
99012853244732DB00C72B10 /* BottomTabBarInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9901284D244732DB00C72B10 /* BottomTabBarInteractor.swift */; };
|
||||
990128562449A82500C72B10 /* BottomTabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 990128552449A82400C72B10 /* BottomTabBarView.swift */; };
|
||||
990F33B624BC915200D0F426 /* SearchActionBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 990F33B524BC915200D0F426 /* SearchActionBarView.swift */; };
|
||||
9917D17F2397B1D600A7E06E /* IPadModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9917D17E2397B1D600A7E06E /* IPadModalPresentationController.swift */; };
|
||||
991FCA2423B11E61009AD684 /* BookmarksStyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 991FCA2323B11E61009AD684 /* BookmarksStyleSheet.swift */; };
|
||||
993DF0B523F6B2EF00AC231A /* PlacePageTrackLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */; };
|
||||
|
@ -396,7 +394,6 @@
|
|||
995F1613244F0AA50060631D /* BottomMenuLayersCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 995F1611244F0AA40060631D /* BottomMenuLayersCell.swift */; };
|
||||
995F1614244F0AA50060631D /* BottomMenuLayersCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 995F1612244F0AA40060631D /* BottomMenuLayersCell.xib */; };
|
||||
996D108A24E3DBF2002DD0E2 /* BookmarksCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 996D108924E3DBF2002DD0E2 /* BookmarksCoordinator.swift */; };
|
||||
9977E69C247BFB510073780C /* SearchTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9977E69B247BFB510073780C /* SearchTextField.swift */; };
|
||||
9977E6A12480E1EE0073780C /* BottomMenuLayerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9977E6A02480E1EE0073780C /* BottomMenuLayerButton.swift */; };
|
||||
9977E6A32480F9BF0073780C /* BottomMenuLayerButtonRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9977E6A22480F9BF0073780C /* BottomMenuLayerButtonRenderer.swift */; };
|
||||
998927302449DE1500260CE2 /* TabBarArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9989272F2449DE1500260CE2 /* TabBarArea.swift */; };
|
||||
|
@ -493,8 +490,21 @@
|
|||
ED4DC7772CAEDECC0029B338 /* ProductsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4DC7752CAEDECC0029B338 /* ProductsViewModel.swift */; };
|
||||
ED4DC7782CAEDECC0029B338 /* ProductButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4DC7732CAEDECC0029B338 /* ProductButton.swift */; };
|
||||
ED4DC7792CAEDECC0029B338 /* ProductsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4DC7742CAEDECC0029B338 /* ProductsViewController.swift */; };
|
||||
ED5BAF4B2D688F5B0088D7B1 /* SearchOnMapHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5BAF4A2D688F5A0088D7B1 /* SearchOnMapHeaderView.swift */; };
|
||||
ED63CEB92BDF8F9D006155C4 /* SettingsTableViewiCloudSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED63CEB62BDF8F9C006155C4 /* SettingsTableViewiCloudSwitchCell.swift */; };
|
||||
ED70D55C2D5396F300738C1E /* SearchResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = ED70D55A2D5396F300738C1E /* SearchResult.mm */; };
|
||||
ED70D5892D539A2500738C1E /* SearchOnMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5872D539A2500738C1E /* SearchOnMapViewController.swift */; };
|
||||
ED70D58A2D539A2500738C1E /* SearchOnMapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5852D539A2500738C1E /* SearchOnMapModels.swift */; };
|
||||
ED70D58B2D539A2500738C1E /* SearchOnMapModalTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D57E2D539A2500738C1E /* SearchOnMapModalTransitionManager.swift */; };
|
||||
ED70D58C2D539A2500738C1E /* SearchOnMapPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5862D539A2500738C1E /* SearchOnMapPresenter.swift */; };
|
||||
ED70D58D2D539A2500738C1E /* ModalScreenPresentationStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D57C2D539A2500738C1E /* ModalScreenPresentationStep.swift */; };
|
||||
ED70D58E2D539A2500738C1E /* SideMenuPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5802D539A2500738C1E /* SideMenuPresentationAnimator.swift */; };
|
||||
ED70D58F2D539A2500738C1E /* SearchOnMapInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5832D539A2500738C1E /* SearchOnMapInteractor.swift */; };
|
||||
ED70D5902D539A2500738C1E /* SearchOnMapModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D57D2D539A2500738C1E /* SearchOnMapModalPresentationController.swift */; };
|
||||
ED70D5912D539A2500738C1E /* MapPassthroughView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D57B2D539A2500738C1E /* MapPassthroughView.swift */; };
|
||||
ED70D5922D539A2500738C1E /* PlaceholderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5822D539A2500738C1E /* PlaceholderView.swift */; };
|
||||
ED70D5932D539A2500738C1E /* SearchOnMapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D5842D539A2500738C1E /* SearchOnMapManager.swift */; };
|
||||
ED70D5942D539A2500738C1E /* SideMenuDismissalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED70D57F2D539A2500738C1E /* SideMenuDismissalAnimator.swift */; };
|
||||
ED77556E2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED77556D2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift */; };
|
||||
ED79A5AB2BD7AA9C00952D1F /* LoadingOverlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5AA2BD7AA9C00952D1F /* LoadingOverlayViewController.swift */; };
|
||||
ED79A5AD2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5AC2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift */; };
|
||||
|
@ -506,6 +516,7 @@
|
|||
ED79A5D82BDF8D6100952D1F /* LocalDirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED79A5D02BDF8D6100952D1F /* LocalDirectoryMonitor.swift */; };
|
||||
ED7CCC4F2C1362E300E2A737 /* FileType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7CCC4E2C1362E300E2A737 /* FileType.swift */; };
|
||||
ED808D0F2C38407800D52585 /* CircleImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED808D0E2C38407800D52585 /* CircleImageButton.swift */; };
|
||||
ED810EC52D566E9B00ECDE2C /* SearchOnMapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED810EC42D566E9B00ECDE2C /* SearchOnMapTests.swift */; };
|
||||
ED8270F02C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */; };
|
||||
ED83880F2D54DEB3002A0536 /* UIImage+FilledWithColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED83880E2D54DEA4002A0536 /* UIImage+FilledWithColor.swift */; };
|
||||
ED914AB22D35063A00973C45 /* TextColorStyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED914AB12D35063A00973C45 /* TextColorStyleSheet.swift */; };
|
||||
|
@ -523,7 +534,6 @@
|
|||
EDC4E3612C5E2576009286A2 /* RecentlyDeletedCategoriesViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC4E3412C5D1BD3009286A2 /* RecentlyDeletedCategoriesViewModelTests.swift */; };
|
||||
EDC4E3692C5E6F5B009286A2 /* MockRecentlyDeletedCategoriesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC4E3402C5D1BD3009286A2 /* MockRecentlyDeletedCategoriesManager.swift */; };
|
||||
EDCA7CDF2D317DF9003366CE /* StyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDCA7CDE2D317DF9003366CE /* StyleSheet.swift */; };
|
||||
EDDE060E2D6CAEAF000C328A /* SearchHistoryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = EDDE060D2D6CAEAF000C328A /* SearchHistoryViewController.xib */; };
|
||||
EDE243DD2B6D2E640057369B /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243D52B6CF3980057369B /* AboutController.swift */; };
|
||||
EDE243E52B6D3F400057369B /* OSMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243E42B6D3F400057369B /* OSMView.swift */; };
|
||||
EDE243E72B6D55610057369B /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE243E02B6D3EA00057369B /* InfoView.swift */; };
|
||||
|
@ -617,20 +627,13 @@
|
|||
F6E2FE7F1E097BA00083EBEC /* MWMPlacePageOpeningHoursCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FCBD1E097B9F0083EBEC /* MWMPlacePageOpeningHoursCell.xib */; };
|
||||
F6E2FE821E097BA00083EBEC /* MWMPlacePageOpeningHoursDayView.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCBF1E097B9F0083EBEC /* MWMPlacePageOpeningHoursDayView.m */; };
|
||||
F6E2FE851E097BA00083EBEC /* MWMPlacePageOpeningHoursWeekDayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FCC01E097B9F0083EBEC /* MWMPlacePageOpeningHoursWeekDayView.xib */; };
|
||||
F6E2FED91E097BA00083EBEC /* MWMSearchContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCF51E097B9F0083EBEC /* MWMSearchContentView.m */; };
|
||||
F6E2FEDF1E097BA00083EBEC /* MWMSearchManager+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCF91E097B9F0083EBEC /* MWMSearchManager+Layout.m */; };
|
||||
F6E2FEE21E097BA00083EBEC /* MWMSearchManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCFB1E097B9F0083EBEC /* MWMSearchManager.mm */; };
|
||||
F6E2FEE51E097BA00083EBEC /* MWMSearchNoResults.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FCFD1E097B9F0083EBEC /* MWMSearchNoResults.m */; };
|
||||
F6E2FEE81E097BA00083EBEC /* MWMSearchNoResults.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FCFE1E097B9F0083EBEC /* MWMSearchNoResults.xib */; };
|
||||
F6E2FEEE1E097BA00083EBEC /* MWMSearchView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FD011E097B9F0083EBEC /* MWMSearchView.xib */; };
|
||||
F6E2FF2D1E097BA00083EBEC /* MWMSearchCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD2A1E097BA00083EBEC /* MWMSearchCell.mm */; };
|
||||
F6E2FF301E097BA00083EBEC /* MWMSearchCommonCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD2C1E097BA00083EBEC /* MWMSearchCommonCell.mm */; };
|
||||
F6E2FF331E097BA00083EBEC /* MWMSearchCommonCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FD2D1E097BA00083EBEC /* MWMSearchCommonCell.xib */; };
|
||||
F6E2FF361E097BA00083EBEC /* MWMSearchSuggestionCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD2F1E097BA00083EBEC /* MWMSearchSuggestionCell.mm */; };
|
||||
F6E2FF391E097BA00083EBEC /* MWMSearchSuggestionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FD301E097BA00083EBEC /* MWMSearchSuggestionCell.xib */; };
|
||||
F6E2FF3C1E097BA00083EBEC /* MWMSearchTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD321E097BA00083EBEC /* MWMSearchTableView.m */; };
|
||||
F6E2FF3F1E097BA00083EBEC /* MWMSearchTableViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD341E097BA00083EBEC /* MWMSearchTableViewController.mm */; };
|
||||
F6E2FF421E097BA00083EBEC /* MWMSearchTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FD351E097BA00083EBEC /* MWMSearchTableViewController.xib */; };
|
||||
F6E2FF451E097BA00083EBEC /* SettingsTableViewLinkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD381E097BA00083EBEC /* SettingsTableViewLinkCell.swift */; };
|
||||
F6E2FF481E097BA00083EBEC /* SettingsTableViewSelectableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD391E097BA00083EBEC /* SettingsTableViewSelectableCell.swift */; };
|
||||
F6E2FF4B1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FD3A1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift */; };
|
||||
|
@ -909,7 +912,6 @@
|
|||
34763EE91F2F394D00F4D2D3 /* MWMTextToSpeech+CPP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MWMTextToSpeech+CPP.h"; sourceTree = "<group>"; };
|
||||
34763EEA1F2F3AD700F4D2D3 /* MWMTextToSpeechObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMTextToSpeechObserver.h; sourceTree = "<group>"; };
|
||||
34763F0B1F30CCAC00F4D2D3 /* MWMEditorCellType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMEditorCellType.h; sourceTree = "<group>"; };
|
||||
347AD8081F28B4E6007ACB68 /* MWMSearchManagerObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchManagerObserver.h; sourceTree = "<group>"; };
|
||||
34845DAD1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderNoResultsEmbedViewController.swift; sourceTree = "<group>"; };
|
||||
34845DB11E165E24003D55B9 /* SearchNoResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchNoResultsViewController.swift; sourceTree = "<group>"; };
|
||||
34845DB51E166084003D55B9 /* Common.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = "<group>"; };
|
||||
|
@ -932,7 +934,6 @@
|
|||
349A35771B53D4C9009677EE /* MWMCircularProgress.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMCircularProgress.xib; sourceTree = "<group>"; };
|
||||
349A35781B53D4C9009677EE /* MWMCircularProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMCircularProgressView.h; sourceTree = "<group>"; };
|
||||
349A35791B53D4C9009677EE /* MWMCircularProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMCircularProgressView.m; sourceTree = "<group>"; };
|
||||
349D1ABA1E2D05EF004A2006 /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
|
||||
349D1AC61E2E325B004A2006 /* BottomMenuItemCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BottomMenuItemCell.xib; sourceTree = "<group>"; };
|
||||
349D1ACD1E2E325B004A2006 /* BottomTabBarViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BottomTabBarViewController.xib; sourceTree = "<group>"; };
|
||||
349D1CE21E3F836900A878FD /* UIViewController+Hierarchy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Hierarchy.swift"; sourceTree = "<group>"; };
|
||||
|
@ -994,7 +995,6 @@
|
|||
34B127E61FBDD358008713D9 /* MWMRouterTransitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMRouterTransitType.h; sourceTree = "<group>"; };
|
||||
34B127E71FBDD410008713D9 /* MWMRouterTransitStepInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMRouterTransitStepInfo.h; sourceTree = "<group>"; };
|
||||
34B127E81FBDD410008713D9 /* MWMRouterTransitStepInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMRouterTransitStepInfo.mm; sourceTree = "<group>"; };
|
||||
34B3806B1F1E46E20087D65B /* MWMSearchManagerState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchManagerState.h; sourceTree = "<group>"; };
|
||||
34B846A02029DCC10081ECCD /* BMCCategoriesHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BMCCategoriesHeader.swift; sourceTree = "<group>"; };
|
||||
34B846A72029E8110081ECCD /* BMCDefaultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BMCDefaultViewModel.swift; sourceTree = "<group>"; };
|
||||
34B924401DC8A29C0008D971 /* MWMMailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMailViewController.h; sourceTree = "<group>"; };
|
||||
|
@ -1252,7 +1252,6 @@
|
|||
9901284C244732DB00C72B10 /* BottomTabBarBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomTabBarBuilder.swift; sourceTree = "<group>"; };
|
||||
9901284D244732DB00C72B10 /* BottomTabBarInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomTabBarInteractor.swift; sourceTree = "<group>"; };
|
||||
990128552449A82400C72B10 /* BottomTabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomTabBarView.swift; sourceTree = "<group>"; };
|
||||
990F33B524BC915200D0F426 /* SearchActionBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchActionBarView.swift; sourceTree = "<group>"; };
|
||||
9917D17E2397B1D600A7E06E /* IPadModalPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPadModalPresentationController.swift; sourceTree = "<group>"; };
|
||||
991FCA2323B11E61009AD684 /* BookmarksStyleSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksStyleSheet.swift; sourceTree = "<group>"; };
|
||||
993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageTrackLayout.swift; sourceTree = "<group>"; };
|
||||
|
@ -1318,7 +1317,6 @@
|
|||
995F1611244F0AA40060631D /* BottomMenuLayersCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomMenuLayersCell.swift; sourceTree = "<group>"; };
|
||||
995F1612244F0AA40060631D /* BottomMenuLayersCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BottomMenuLayersCell.xib; sourceTree = "<group>"; };
|
||||
996D108924E3DBF2002DD0E2 /* BookmarksCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksCoordinator.swift; sourceTree = "<group>"; };
|
||||
9977E69B247BFB510073780C /* SearchTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTextField.swift; sourceTree = "<group>"; };
|
||||
9977E6A02480E1EE0073780C /* BottomMenuLayerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomMenuLayerButton.swift; sourceTree = "<group>"; };
|
||||
9977E6A22480F9BF0073780C /* BottomMenuLayerButtonRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomMenuLayerButtonRenderer.swift; sourceTree = "<group>"; };
|
||||
9989272F2449DE1500260CE2 /* TabBarArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarArea.swift; sourceTree = "<group>"; };
|
||||
|
@ -1455,11 +1453,24 @@
|
|||
ED4DC7732CAEDECC0029B338 /* ProductButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductButton.swift; sourceTree = "<group>"; };
|
||||
ED4DC7742CAEDECC0029B338 /* ProductsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsViewController.swift; sourceTree = "<group>"; };
|
||||
ED4DC7752CAEDECC0029B338 /* ProductsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsViewModel.swift; sourceTree = "<group>"; };
|
||||
ED5BAF4A2D688F5A0088D7B1 /* SearchOnMapHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapHeaderView.swift; sourceTree = "<group>"; };
|
||||
ED63CEB62BDF8F9C006155C4 /* SettingsTableViewiCloudSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewiCloudSwitchCell.swift; sourceTree = "<group>"; };
|
||||
ED70D5582D5396F300738C1E /* SearchItemType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SearchItemType.h; sourceTree = "<group>"; };
|
||||
ED70D5592D5396F300738C1E /* SearchResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SearchResult.h; sourceTree = "<group>"; };
|
||||
ED70D55A2D5396F300738C1E /* SearchResult.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SearchResult.mm; sourceTree = "<group>"; };
|
||||
ED70D55B2D5396F300738C1E /* SearchResult+Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SearchResult+Core.h"; sourceTree = "<group>"; };
|
||||
ED70D57B2D539A2500738C1E /* MapPassthroughView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapPassthroughView.swift; sourceTree = "<group>"; };
|
||||
ED70D57C2D539A2500738C1E /* ModalScreenPresentationStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalScreenPresentationStep.swift; sourceTree = "<group>"; };
|
||||
ED70D57D2D539A2500738C1E /* SearchOnMapModalPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapModalPresentationController.swift; sourceTree = "<group>"; };
|
||||
ED70D57E2D539A2500738C1E /* SearchOnMapModalTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapModalTransitionManager.swift; sourceTree = "<group>"; };
|
||||
ED70D57F2D539A2500738C1E /* SideMenuDismissalAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuDismissalAnimator.swift; sourceTree = "<group>"; };
|
||||
ED70D5802D539A2500738C1E /* SideMenuPresentationAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuPresentationAnimator.swift; sourceTree = "<group>"; };
|
||||
ED70D5822D539A2500738C1E /* PlaceholderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderView.swift; sourceTree = "<group>"; };
|
||||
ED70D5832D539A2500738C1E /* SearchOnMapInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapInteractor.swift; sourceTree = "<group>"; };
|
||||
ED70D5842D539A2500738C1E /* SearchOnMapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapManager.swift; sourceTree = "<group>"; };
|
||||
ED70D5852D539A2500738C1E /* SearchOnMapModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapModels.swift; sourceTree = "<group>"; };
|
||||
ED70D5862D539A2500738C1E /* SearchOnMapPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapPresenter.swift; sourceTree = "<group>"; };
|
||||
ED70D5872D539A2500738C1E /* SearchOnMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapViewController.swift; sourceTree = "<group>"; };
|
||||
ED77556D2C2C490B0051E656 /* UIAlertController+openInAppActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+openInAppActionSheet.swift"; sourceTree = "<group>"; };
|
||||
ED79A5AA2BD7AA9C00952D1F /* LoadingOverlayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingOverlayViewController.swift; sourceTree = "<group>"; };
|
||||
ED79A5AC2BD7BA0F00952D1F /* UIApplication+LoadingOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+LoadingOverlay.swift"; sourceTree = "<group>"; };
|
||||
|
@ -1471,6 +1482,7 @@
|
|||
ED79A5D02BDF8D6100952D1F /* LocalDirectoryMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalDirectoryMonitor.swift; sourceTree = "<group>"; };
|
||||
ED7CCC4E2C1362E300E2A737 /* FileType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileType.swift; sourceTree = "<group>"; };
|
||||
ED808D0E2C38407800D52585 /* CircleImageButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleImageButton.swift; sourceTree = "<group>"; };
|
||||
ED810EC42D566E9B00ECDE2C /* SearchOnMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOnMapTests.swift; sourceTree = "<group>"; };
|
||||
ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewDetailedSwitchCell.swift; sourceTree = "<group>"; };
|
||||
ED83880E2D54DEA4002A0536 /* UIImage+FilledWithColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+FilledWithColor.swift"; sourceTree = "<group>"; };
|
||||
ED914AB12D35063A00973C45 /* TextColorStyleSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextColorStyleSheet.swift; sourceTree = "<group>"; };
|
||||
|
@ -1488,7 +1500,6 @@
|
|||
EDC4E3482C5D1BEF009286A2 /* RecentlyDeletedCategoriesViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentlyDeletedCategoriesViewModel.swift; sourceTree = "<group>"; };
|
||||
EDC4E3492C5D1BEF009286A2 /* RecentlyDeletedTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentlyDeletedTableViewCell.swift; sourceTree = "<group>"; };
|
||||
EDCA7CDE2D317DF9003366CE /* StyleSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyleSheet.swift; sourceTree = "<group>"; };
|
||||
EDDE060D2D6CAEAF000C328A /* SearchHistoryViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SearchHistoryViewController.xib; sourceTree = "<group>"; };
|
||||
EDE243D52B6CF3980057369B /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = "<group>"; };
|
||||
EDE243E02B6D3EA00057369B /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = "<group>"; };
|
||||
EDE243E42B6D3F400057369B /* OSMView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSMView.swift; sourceTree = "<group>"; };
|
||||
|
@ -1664,17 +1675,9 @@
|
|||
F6E2FCBE1E097B9F0083EBEC /* MWMPlacePageOpeningHoursDayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMPlacePageOpeningHoursDayView.h; sourceTree = "<group>"; };
|
||||
F6E2FCBF1E097B9F0083EBEC /* MWMPlacePageOpeningHoursDayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMPlacePageOpeningHoursDayView.m; sourceTree = "<group>"; };
|
||||
F6E2FCC01E097B9F0083EBEC /* MWMPlacePageOpeningHoursWeekDayView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMPlacePageOpeningHoursWeekDayView.xib; sourceTree = "<group>"; };
|
||||
F6E2FCF41E097B9F0083EBEC /* MWMSearchContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchContentView.h; sourceTree = "<group>"; };
|
||||
F6E2FCF51E097B9F0083EBEC /* MWMSearchContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMSearchContentView.m; sourceTree = "<group>"; };
|
||||
F6E2FCF81E097B9F0083EBEC /* MWMSearchManager+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MWMSearchManager+Layout.h"; sourceTree = "<group>"; };
|
||||
F6E2FCF91E097B9F0083EBEC /* MWMSearchManager+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MWMSearchManager+Layout.m"; sourceTree = "<group>"; };
|
||||
F6E2FCFA1E097B9F0083EBEC /* MWMSearchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchManager.h; sourceTree = "<group>"; };
|
||||
F6E2FCFB1E097B9F0083EBEC /* MWMSearchManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSearchManager.mm; sourceTree = "<group>"; };
|
||||
F6E2FCFC1E097B9F0083EBEC /* MWMSearchNoResults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchNoResults.h; sourceTree = "<group>"; };
|
||||
F6E2FCFD1E097B9F0083EBEC /* MWMSearchNoResults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MWMSearchNoResults.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
F6E2FCFE1E097B9F0083EBEC /* MWMSearchNoResults.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMSearchNoResults.xib; sourceTree = "<group>"; };
|
||||
F6E2FD011E097B9F0083EBEC /* MWMSearchView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMSearchView.xib; sourceTree = "<group>"; };
|
||||
F6E2FD231E097BA00083EBEC /* MWMSearchTabbedViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchTabbedViewProtocol.h; sourceTree = "<group>"; };
|
||||
F6E2FD291E097BA00083EBEC /* MWMSearchCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchCell.h; sourceTree = "<group>"; };
|
||||
F6E2FD2A1E097BA00083EBEC /* MWMSearchCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSearchCell.mm; sourceTree = "<group>"; };
|
||||
F6E2FD2B1E097BA00083EBEC /* MWMSearchCommonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchCommonCell.h; sourceTree = "<group>"; };
|
||||
|
@ -1683,11 +1686,6 @@
|
|||
F6E2FD2E1E097BA00083EBEC /* MWMSearchSuggestionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchSuggestionCell.h; sourceTree = "<group>"; };
|
||||
F6E2FD2F1E097BA00083EBEC /* MWMSearchSuggestionCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMSearchSuggestionCell.mm; sourceTree = "<group>"; };
|
||||
F6E2FD301E097BA00083EBEC /* MWMSearchSuggestionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMSearchSuggestionCell.xib; sourceTree = "<group>"; };
|
||||
F6E2FD311E097BA00083EBEC /* MWMSearchTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchTableView.h; sourceTree = "<group>"; };
|
||||
F6E2FD321E097BA00083EBEC /* MWMSearchTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMSearchTableView.m; sourceTree = "<group>"; };
|
||||
F6E2FD331E097BA00083EBEC /* MWMSearchTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMSearchTableViewController.h; sourceTree = "<group>"; };
|
||||
F6E2FD341E097BA00083EBEC /* MWMSearchTableViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMSearchTableViewController.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
F6E2FD351E097BA00083EBEC /* MWMSearchTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMSearchTableViewController.xib; sourceTree = "<group>"; };
|
||||
F6E2FD381E097BA00083EBEC /* SettingsTableViewLinkCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewLinkCell.swift; sourceTree = "<group>"; };
|
||||
F6E2FD391E097BA00083EBEC /* SettingsTableViewSelectableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSelectableCell.swift; sourceTree = "<group>"; };
|
||||
F6E2FD3A1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsTableViewSwitchCell.swift; sourceTree = "<group>"; };
|
||||
|
@ -3180,6 +3178,7 @@
|
|||
ED1ADA312BC6B19E0029209F /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED810EC02D566E6F00ECDE2C /* UI */,
|
||||
EDC4E3442C5D1BD3009286A2 /* Bookmarks */,
|
||||
4B4153B82BF970B800EE4B02 /* Classes */,
|
||||
4B4153B62BF9709100EE4B02 /* Core */,
|
||||
|
@ -3231,6 +3230,34 @@
|
|||
path = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED70D5812D539A2500738C1E /* Presentation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED70D57B2D539A2500738C1E /* MapPassthroughView.swift */,
|
||||
ED70D57C2D539A2500738C1E /* ModalScreenPresentationStep.swift */,
|
||||
ED70D57D2D539A2500738C1E /* SearchOnMapModalPresentationController.swift */,
|
||||
ED70D57E2D539A2500738C1E /* SearchOnMapModalTransitionManager.swift */,
|
||||
ED70D57F2D539A2500738C1E /* SideMenuDismissalAnimator.swift */,
|
||||
ED70D5802D539A2500738C1E /* SideMenuPresentationAnimator.swift */,
|
||||
);
|
||||
path = Presentation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED70D5882D539A2500738C1E /* SearchOnMap */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED70D5812D539A2500738C1E /* Presentation */,
|
||||
ED70D5822D539A2500738C1E /* PlaceholderView.swift */,
|
||||
ED70D5832D539A2500738C1E /* SearchOnMapInteractor.swift */,
|
||||
ED70D5842D539A2500738C1E /* SearchOnMapManager.swift */,
|
||||
ED70D5852D539A2500738C1E /* SearchOnMapModels.swift */,
|
||||
ED70D5862D539A2500738C1E /* SearchOnMapPresenter.swift */,
|
||||
ED70D5872D539A2500738C1E /* SearchOnMapViewController.swift */,
|
||||
ED5BAF4A2D688F5A0088D7B1 /* SearchOnMapHeaderView.swift */,
|
||||
);
|
||||
path = SearchOnMap;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED79A5A92BD7AA7500952D1F /* LoadingOverlay */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3253,6 +3280,22 @@
|
|||
path = iCloud;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED810EC02D566E6F00ECDE2C /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED810EC32D566E7600ECDE2C /* SearchOnMapTests */,
|
||||
);
|
||||
path = UI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED810EC32D566E7600ECDE2C /* SearchOnMapTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED810EC42D566E9B00ECDE2C /* SearchOnMapTests.swift */,
|
||||
);
|
||||
path = SearchOnMapTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ED9857022C4ECFFC00694F6C /* MailComposer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3822,24 +3865,13 @@
|
|||
F6E2FCE11E097B9F0083EBEC /* Search */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F6E2FCF41E097B9F0083EBEC /* MWMSearchContentView.h */,
|
||||
F6E2FCF51E097B9F0083EBEC /* MWMSearchContentView.m */,
|
||||
F6E2FCF81E097B9F0083EBEC /* MWMSearchManager+Layout.h */,
|
||||
F6E2FCF91E097B9F0083EBEC /* MWMSearchManager+Layout.m */,
|
||||
F6E2FCFA1E097B9F0083EBEC /* MWMSearchManager.h */,
|
||||
F6E2FCFB1E097B9F0083EBEC /* MWMSearchManager.mm */,
|
||||
ED70D5882D539A2500738C1E /* SearchOnMap */,
|
||||
F6E2FCFC1E097B9F0083EBEC /* MWMSearchNoResults.h */,
|
||||
F6E2FCFD1E097B9F0083EBEC /* MWMSearchNoResults.m */,
|
||||
F6E2FCFE1E097B9F0083EBEC /* MWMSearchNoResults.xib */,
|
||||
9977E69B247BFB510073780C /* SearchTextField.swift */,
|
||||
F6E2FD011E097B9F0083EBEC /* MWMSearchView.xib */,
|
||||
F6E2FD021E097B9F0083EBEC /* Tabs */,
|
||||
F6E2FD281E097BA00083EBEC /* TableView */,
|
||||
34845DB11E165E24003D55B9 /* SearchNoResultsViewController.swift */,
|
||||
349D1ABA1E2D05EF004A2006 /* SearchBar.swift */,
|
||||
34B3806B1F1E46E20087D65B /* MWMSearchManagerState.h */,
|
||||
347AD8081F28B4E6007ACB68 /* MWMSearchManagerObserver.h */,
|
||||
990F33B524BC915200D0F426 /* SearchActionBarView.swift */,
|
||||
475ED78724C7D0F30063ADC7 /* ValueStepperView.swift */,
|
||||
);
|
||||
path = Search;
|
||||
|
@ -3850,7 +3882,6 @@
|
|||
children = (
|
||||
F6E2FD091E097B9F0083EBEC /* CategoriesTab */,
|
||||
F6E2FD0F1E097B9F0083EBEC /* HistoryTab */,
|
||||
F6E2FD231E097BA00083EBEC /* MWMSearchTabbedViewProtocol.h */,
|
||||
337F98A521D37B7400C8AC27 /* SearchTabViewController.swift */,
|
||||
);
|
||||
path = Tabs;
|
||||
|
@ -3868,7 +3899,6 @@
|
|||
F6E2FD0F1E097B9F0083EBEC /* HistoryTab */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EDDE060D2D6CAEAF000C328A /* SearchHistoryViewController.xib */,
|
||||
337F98B721D3D67E00C8AC27 /* SearchHistoryCell.swift */,
|
||||
337F98B321D3C9F200C8AC27 /* SearchHistoryViewController.swift */,
|
||||
);
|
||||
|
@ -3886,11 +3916,6 @@
|
|||
F6E2FD2E1E097BA00083EBEC /* MWMSearchSuggestionCell.h */,
|
||||
F6E2FD2F1E097BA00083EBEC /* MWMSearchSuggestionCell.mm */,
|
||||
F6E2FD301E097BA00083EBEC /* MWMSearchSuggestionCell.xib */,
|
||||
F6E2FD311E097BA00083EBEC /* MWMSearchTableView.h */,
|
||||
F6E2FD321E097BA00083EBEC /* MWMSearchTableView.m */,
|
||||
F6E2FD331E097BA00083EBEC /* MWMSearchTableViewController.h */,
|
||||
F6E2FD341E097BA00083EBEC /* MWMSearchTableViewController.mm */,
|
||||
F6E2FD351E097BA00083EBEC /* MWMSearchTableViewController.xib */,
|
||||
);
|
||||
path = TableView;
|
||||
sourceTree = "<group>";
|
||||
|
@ -4266,7 +4291,6 @@
|
|||
6741A9991BF340DE002C974C /* MWMAlertViewController.xib in Resources */,
|
||||
4501B1942077C35A001B9173 /* resources-xxxhdpi_light in Resources */,
|
||||
3467CEB7202C6FA900D3C670 /* BMCNotificationsCell.xib in Resources */,
|
||||
EDDE060E2D6CAEAF000C328A /* SearchHistoryViewController.xib in Resources */,
|
||||
4761BE2B252D3DB900EE2DE4 /* SubgroupCell.xib in Resources */,
|
||||
99F9A0E72462CA1700AE21E0 /* DownloadAllView.xib in Resources */,
|
||||
349D1AD51E2E325B004A2006 /* BottomMenuItemCell.xib in Resources */,
|
||||
|
@ -4338,9 +4362,7 @@
|
|||
F6E2FF391E097BA00083EBEC /* MWMSearchSuggestionCell.xib in Resources */,
|
||||
34AB66231FC5AA330078E451 /* MWMiPadRoutePreview.xib in Resources */,
|
||||
BB25B1A71FB32767007276FA /* transit_colors.txt in Resources */,
|
||||
F6E2FF421E097BA00083EBEC /* MWMSearchTableViewController.xib in Resources */,
|
||||
34AB66681FC5AA330078E451 /* TransportTransitPedestrian.xib in Resources */,
|
||||
F6E2FEEE1E097BA00083EBEC /* MWMSearchView.xib in Resources */,
|
||||
4501B1952077C35A001B9173 /* resources-xxxhdpi_dark in Resources */,
|
||||
F6D67CDE2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib in Resources */,
|
||||
3490D2E31CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */,
|
||||
|
@ -4431,7 +4453,6 @@
|
|||
34D3AFF61E37A36A004100F9 /* UICollectionView+Cells.swift in Sources */,
|
||||
4767CDA420AAF66B00BD8166 /* NSAttributedString+HTML.swift in Sources */,
|
||||
6741A9A91BF340DE002C974C /* MWMDefaultAlert.mm in Sources */,
|
||||
990F33B624BC915200D0F426 /* SearchActionBarView.swift in Sources */,
|
||||
99514BBA23E82B450085D3A7 /* ElevationProfileViewController.swift in Sources */,
|
||||
340708781F2B5D6C00029ECC /* DimBackground.swift in Sources */,
|
||||
3490D2DF1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */,
|
||||
|
@ -4483,8 +4504,6 @@
|
|||
6741A9B81BF340DE002C974C /* MapViewController.mm in Sources */,
|
||||
34AB662C1FC5AA330078E451 /* RouteManagerViewModel.swift in Sources */,
|
||||
3404F48B202894EA0090E401 /* BMCViewController.swift in Sources */,
|
||||
349D1ABC1E2D05EF004A2006 /* SearchBar.swift in Sources */,
|
||||
F6E2FF3F1E097BA00083EBEC /* MWMSearchTableViewController.mm in Sources */,
|
||||
F6E2FDE01E097BA00083EBEC /* MWMEditorViewController.mm in Sources */,
|
||||
6741A9C01BF340DE002C974C /* MWMTextView.m in Sources */,
|
||||
F6E2FDB61E097BA00083EBEC /* MWMEditorAdditionalNamesHeader.m in Sources */,
|
||||
|
@ -4522,7 +4541,6 @@
|
|||
F6791B141C43DF0B007A8A6E /* MWMStartButton.m in Sources */,
|
||||
9977E6A12480E1EE0073780C /* BottomMenuLayerButton.swift in Sources */,
|
||||
471527372491C20500E91BBA /* SelectBookmarkGroupViewController.swift in Sources */,
|
||||
F6E2FEDF1E097BA00083EBEC /* MWMSearchManager+Layout.m in Sources */,
|
||||
F64D9CA01C899C350063FA30 /* MWMEditorViralAlert.mm in Sources */,
|
||||
34AC8FD11EFC02C000E7F910 /* MWMRoutePoint.mm in Sources */,
|
||||
CDB4D5012231412900104869 /* ListTemplateBuilder.swift in Sources */,
|
||||
|
@ -4556,6 +4574,7 @@
|
|||
ED43B8BD2C12063500D07BAA /* DocumentPicker.swift in Sources */,
|
||||
470E1674252AD7F2002D201A /* BookmarksListInfoViewController.swift in Sources */,
|
||||
47B9065521C7FA400079C85E /* NSString+MD5.m in Sources */,
|
||||
ED5BAF4B2D688F5B0088D7B1 /* SearchOnMapHeaderView.swift in Sources */,
|
||||
CDB4D5022231412900104869 /* SettingsTemplateBuilder.swift in Sources */,
|
||||
993DF10A23F6BDB100AC231A /* UISwitchRenderer.swift in Sources */,
|
||||
99C9642C2428C0F700E41723 /* PlacePageHeaderBuilder.swift in Sources */,
|
||||
|
@ -4683,7 +4702,6 @@
|
|||
3472B5CF200F4A2B00DC6CD5 /* BackgroundFetchTask.swift in Sources */,
|
||||
477219052243E79500E5B227 /* DrivingOptionsViewController.swift in Sources */,
|
||||
CDB4D4E4222E8FF600104869 /* CarPlayService.swift in Sources */,
|
||||
F6E2FF3C1E097BA00083EBEC /* MWMSearchTableView.m in Sources */,
|
||||
F6E2FF661E097BA00083EBEC /* MWMTTSSettingsViewController.mm in Sources */,
|
||||
3454D7C21E07F045004AF2AD /* NSString+Categories.m in Sources */,
|
||||
ED2D74662D1435A600660FBF /* LiveActivityManager.swift in Sources */,
|
||||
|
@ -4735,12 +4753,23 @@
|
|||
CD9AD96C2281B56900EC174A /* CPViewPortState.swift in Sources */,
|
||||
EDE243DD2B6D2E640057369B /* AboutController.swift in Sources */,
|
||||
3404755C1E081A4600C92850 /* MWMLocationManager.mm in Sources */,
|
||||
ED70D5892D539A2500738C1E /* SearchOnMapViewController.swift in Sources */,
|
||||
ED70D58A2D539A2500738C1E /* SearchOnMapModels.swift in Sources */,
|
||||
ED70D58B2D539A2500738C1E /* SearchOnMapModalTransitionManager.swift in Sources */,
|
||||
ED70D58C2D539A2500738C1E /* SearchOnMapPresenter.swift in Sources */,
|
||||
ED70D58D2D539A2500738C1E /* ModalScreenPresentationStep.swift in Sources */,
|
||||
ED70D58E2D539A2500738C1E /* SideMenuPresentationAnimator.swift in Sources */,
|
||||
ED70D58F2D539A2500738C1E /* SearchOnMapInteractor.swift in Sources */,
|
||||
ED70D5902D539A2500738C1E /* SearchOnMapModalPresentationController.swift in Sources */,
|
||||
ED70D5912D539A2500738C1E /* MapPassthroughView.swift in Sources */,
|
||||
ED70D5922D539A2500738C1E /* PlaceholderView.swift in Sources */,
|
||||
ED70D5932D539A2500738C1E /* SearchOnMapManager.swift in Sources */,
|
||||
ED70D5942D539A2500738C1E /* SideMenuDismissalAnimator.swift in Sources */,
|
||||
3454D7BC1E07F045004AF2AD /* CLLocation+Mercator.mm in Sources */,
|
||||
47E3C7272111E5A8008B3B27 /* AlertPresentationController.swift in Sources */,
|
||||
CDCA27812243F59800167D87 /* CarPlayRouter.swift in Sources */,
|
||||
34F5E0D41E3F254800B1C415 /* UIView+Hierarchy.swift in Sources */,
|
||||
6741AA0B1BF340DE002C974C /* MWMMapViewControlsManager.mm in Sources */,
|
||||
F6E2FED91E097BA00083EBEC /* MWMSearchContentView.m in Sources */,
|
||||
EDFDFB4C2B722C9C0013A44C /* InfoTableViewCell.swift in Sources */,
|
||||
47CA68F8250F8AB700671019 /* BookmarksListSectionHeader.swift in Sources */,
|
||||
F6BD1D211CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */,
|
||||
|
@ -4767,7 +4796,6 @@
|
|||
4767CDA820AB401000BD8166 /* LinkTextView.swift in Sources */,
|
||||
34763EE71F2F392300F4D2D3 /* MWMTextToSpeech.mm in Sources */,
|
||||
998927402449ECC200260CE2 /* BottomMenuItemCell.swift in Sources */,
|
||||
F6E2FEE21E097BA00083EBEC /* MWMSearchManager.mm in Sources */,
|
||||
F6E2FE221E097BA00083EBEC /* MWMOpeningHoursEditorViewController.mm in Sources */,
|
||||
ED79A5D72BDF8D6100952D1F /* SynchronizationStateResolver.swift in Sources */,
|
||||
999FC12B23ABB4B800B0E6F9 /* FontStyleSheet.swift in Sources */,
|
||||
|
@ -4794,7 +4822,6 @@
|
|||
34B127EA1FBDD410008713D9 /* MWMRouterTransitStepInfo.mm in Sources */,
|
||||
34D3B02A1E389D05004100F9 /* MWMEditorAdditionalNameTableViewCell.m in Sources */,
|
||||
993DF10523F6BDB100AC231A /* UINavigationItem+StyleStyle.swift in Sources */,
|
||||
9977E69C247BFB510073780C /* SearchTextField.swift in Sources */,
|
||||
4726254921C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift in Sources */,
|
||||
039371B62C5B68CD00708377 /* UIFont+monospaced.swift in Sources */,
|
||||
447DB4BC2BA78282000DF4C2 /* MWMOsmReauthAlert.mm in Sources */,
|
||||
|
@ -4881,6 +4908,7 @@
|
|||
EDF838BE2C00B9D0007E4E67 /* LocalDirectoryMonitorDelegateMock.swift in Sources */,
|
||||
EDC4E3692C5E6F5B009286A2 /* MockRecentlyDeletedCategoriesManager.swift in Sources */,
|
||||
EDF838BF2C00B9D0007E4E67 /* SynchronizationStateManagerTests.swift in Sources */,
|
||||
ED810EC52D566E9B00ECDE2C /* SearchOnMapTests.swift in Sources */,
|
||||
4B83AE4B2C2E642100B0C3BC /* TTSTesterTest.m in Sources */,
|
||||
EDF838C22C00B9D6007E4E67 /* MetadataItemStubs.swift in Sources */,
|
||||
EDC4E3612C5E2576009286A2 /* RecentlyDeletedCategoriesViewModelTests.swift in Sources */,
|
||||
|
|
262
iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift
Normal file
262
iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift
Normal file
|
@ -0,0 +1,262 @@
|
|||
import XCTest
|
||||
@testable import Organic_Maps__Debug_
|
||||
|
||||
final class SearchOnMapTests: XCTestCase {
|
||||
|
||||
private var presenter: SearchOnMapPresenter!
|
||||
private var interactor: SearchOnMapInteractor!
|
||||
private var view: SearchOnMapViewMock!
|
||||
private var searchManager: SearchManagerMock.Type!
|
||||
private var currentState: SearchOnMapState = .searching
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
searchManager = SearchManagerMock.self
|
||||
presenter = SearchOnMapPresenter(transitionManager: SearchOnMapModalTransitionManager(),
|
||||
isRouting: false,
|
||||
didChangeState: { [weak self] in self?.currentState = $0 })
|
||||
interactor = SearchOnMapInteractor(presenter: presenter, searchManager: searchManager)
|
||||
view = SearchOnMapViewMock()
|
||||
presenter.view = view
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
presenter = nil
|
||||
interactor = nil
|
||||
view = nil
|
||||
searchManager.results = .empty
|
||||
searchManager = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func test_GivenViewIsLoading_WhenViewLoads_ThenShowsHistoryAndCategory() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
XCTAssertEqual(currentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .historyAndCategory)
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
}
|
||||
|
||||
func test_GivenInitialState_WhenSelectCategory_ThenUpdateSearchResultsAndShowMap() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("category")
|
||||
interactor.handle(.didSelectText(searchText, isCategory: true))
|
||||
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.searchingText, searchText.text)
|
||||
XCTAssertEqual(view.viewModel.isTyping, false)
|
||||
|
||||
let results = SearchResult.stubResults()
|
||||
searchManager.results = results
|
||||
|
||||
XCTAssertEqual(currentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .results(results))
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, false)
|
||||
}
|
||||
|
||||
func test_GivenInitialState_WhenTypeText_ThenUpdateSearchResults() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
|
||||
let results = SearchResult.stubResults()
|
||||
searchManager.results = results
|
||||
|
||||
XCTAssertEqual(currentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .results(results))
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
}
|
||||
|
||||
func test_GivenInitialState_WhenTapSearch_ThenUpdateSearchResultsAndShowMap() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
let results = SearchResult.stubResults()
|
||||
searchManager.results = results
|
||||
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .results(results))
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
|
||||
interactor.handle(.searchButtonDidTap(searchText))
|
||||
|
||||
XCTAssertEqual(currentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .results(results))
|
||||
XCTAssertEqual(view.viewModel.searchingText, nil)
|
||||
XCTAssertEqual(view.viewModel.isTyping, false)
|
||||
}
|
||||
|
||||
func test_GivenSearchIsOpened_WhenMapIsDragged_ThenCollapseSearchScreen() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
|
||||
interactor.handle(.didStartDraggingMap)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .compact)
|
||||
}
|
||||
|
||||
func test_GivenSearchIsOpened_WhenModalPresentationScreenIsDragged_ThenDisableTyping() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
|
||||
interactor.handle(.didStartDraggingSearch)
|
||||
XCTAssertEqual(view.viewModel.isTyping, false)
|
||||
}
|
||||
|
||||
func test_GivenResultsOnScreen_WhenSelectResult_ThenHideSearch() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
let results = SearchResult.stubResults()
|
||||
searchManager.results = results
|
||||
|
||||
interactor.handle(.didSelectResult(results[0], atIndex: 0, withSearchText: searchText))
|
||||
XCTAssertEqual(currentState, .hidden)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .hidden)
|
||||
}
|
||||
|
||||
func test_GivenSearchIsActive_WhenSelectPlaceOnMap_ThenHideSearch() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
|
||||
interactor.handle(.didSelectPlaceOnMap)
|
||||
|
||||
if isIPad {
|
||||
XCTAssertNotEqual(view.viewModel.presentationStep, .hidden)
|
||||
} else {
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .hidden)
|
||||
}
|
||||
}
|
||||
|
||||
func test_GivenSearchIsHidden_WhenPPDeselected_ThenShowSearch() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
let results = SearchResult.stubResults()
|
||||
searchManager.results = results
|
||||
|
||||
interactor.handle(.didSelectResult(results[0], atIndex: 0, withSearchText: searchText))
|
||||
XCTAssertEqual(currentState, .hidden)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .hidden)
|
||||
|
||||
interactor.handle(.didDeselectPlaceOnMap)
|
||||
XCTAssertEqual(currentState, .searching)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
|
||||
}
|
||||
|
||||
func test_GivenSearchIsOpen_WhenCloseSearch_ThenHideSearch() {
|
||||
interactor.handle(.openSearch)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
|
||||
interactor.handle(.closeSearch)
|
||||
XCTAssertEqual(currentState, .closed)
|
||||
}
|
||||
|
||||
func test_GivenSearchHasText_WhenClearSearch_ThenShowHistoryAndCategory() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
interactor.handle(.clearButtonDidTap)
|
||||
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
|
||||
XCTAssertEqual(view.viewModel.contentState, .historyAndCategory)
|
||||
XCTAssertEqual(view.viewModel.searchingText, "")
|
||||
XCTAssertEqual(view.viewModel.isTyping, true)
|
||||
}
|
||||
|
||||
func test_GivenSearchExecuted_WhenNoResults_ThenShowNoResults() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("text")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
searchManager.results = SearchOnMap.SearchResults([])
|
||||
interactor.onSearchCompleted()
|
||||
|
||||
XCTAssertEqual(view.viewModel.contentState, .noResults)
|
||||
}
|
||||
|
||||
func test_GivenSearchIsActive_WhenSelectSuggestion_ThenSearchAgain() {
|
||||
interactor.handle(.openSearch)
|
||||
|
||||
let searchText = SearchOnMap.SearchText("old search")
|
||||
interactor.handle(.didType(searchText))
|
||||
|
||||
let suggestion = SearchResult(titleText: "", type: .suggestion, suggestion: "suggestion")
|
||||
interactor.handle(.didSelectResult(suggestion, atIndex: 0, withSearchText: searchText))
|
||||
|
||||
XCTAssertEqual(view.viewModel.searchingText, "suggestion")
|
||||
XCTAssertEqual(view.viewModel.contentState, .searching)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mocks
|
||||
|
||||
private class SearchOnMapViewMock: SearchOnMapView {
|
||||
var viewModel: SearchOnMap.ViewModel = .initial
|
||||
var scrollViewDelegate: (any SearchOnMapScrollViewDelegate)?
|
||||
func render(_ viewModel: SearchOnMap.ViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchManagerMock: SearchManager {
|
||||
static var observers = ListenerContainer<MWMSearchObserver>()
|
||||
static var results = SearchOnMap.SearchResults.empty {
|
||||
didSet {
|
||||
observers.forEach { observer in
|
||||
observer.onSearchCompleted?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func add(_ observer: any MWMSearchObserver) {
|
||||
self.observers.addListener(observer)
|
||||
}
|
||||
|
||||
static func remove(_ observer: any MWMSearchObserver) {
|
||||
self.observers.removeListener(observer)
|
||||
}
|
||||
|
||||
static func saveQuery(_ query: String, forInputLocale inputLocale: String) {}
|
||||
static func searchQuery(_ query: String, forInputLocale inputLocale: String, withCategory isCategory: Bool) {}
|
||||
static func showResult(at index: UInt) {}
|
||||
static func showEverywhereSearchResultsOnMap() {}
|
||||
static func showViewportSearchResultsOnMap() {}
|
||||
static func clear() {}
|
||||
static func getResults() -> [SearchResult] { results.results }
|
||||
}
|
||||
|
||||
private extension SearchResult {
|
||||
static func stubResults() -> SearchOnMap.SearchResults {
|
||||
SearchOnMap.SearchResults([
|
||||
SearchResult(),
|
||||
SearchResult(),
|
||||
SearchResult()
|
||||
])
|
||||
}
|
||||
}
|
|
@ -11,22 +11,19 @@ class BottomTabBarInteractor {
|
|||
private weak var viewController: UIViewController?
|
||||
private weak var mapViewController: MapViewController?
|
||||
private weak var controlsManager: MWMMapViewControlsManager?
|
||||
private weak var searchManager = MWMSearchManager.manager()
|
||||
|
||||
private let searchManager: SearchOnMapManager
|
||||
|
||||
init(viewController: UIViewController, mapViewController: MapViewController, controlsManager: MWMMapViewControlsManager) {
|
||||
self.viewController = viewController
|
||||
self.mapViewController = mapViewController
|
||||
self.controlsManager = controlsManager
|
||||
self.searchManager = mapViewController.searchManager
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomTabBarInteractor: BottomTabBarInteractorProtocol {
|
||||
func openSearch() {
|
||||
if searchManager?.state == .hidden {
|
||||
searchManager?.state = .default
|
||||
} else {
|
||||
searchManager?.state = .hidden
|
||||
}
|
||||
searchManager.isSearching ? searchManager.close() : searchManager.startSearching(isRouting: false)
|
||||
}
|
||||
|
||||
func openHelp() {
|
||||
|
|
|
@ -32,8 +32,6 @@ class BottomTabBarViewController: UIViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
presenter.configure()
|
||||
|
||||
MWMSearchManager.add(self)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
@ -45,10 +43,6 @@ class BottomTabBarViewController: UIViewController {
|
|||
updateBadge()
|
||||
}
|
||||
|
||||
deinit {
|
||||
MWMSearchManager.remove(self)
|
||||
}
|
||||
|
||||
static func updateAvailableArea(_ frame: CGRect) {
|
||||
BottomTabBarViewController.controller?.updateAvailableArea(frame)
|
||||
}
|
||||
|
@ -119,11 +113,3 @@ private extension BottomTabBarViewController {
|
|||
UserDefaults.standard.set(true, forKey: kUDDidShowFirstTimeRoutingEducationalHint)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MWMSearchManagerObserver
|
||||
extension BottomTabBarViewController: MWMSearchManagerObserver {
|
||||
func onSearchManagerStateChanged() {
|
||||
let state = MWMSearchManager.manager().state;
|
||||
self.searchButton.isSelected = state != .hidden
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
@interface MWMSearchContentView : SolidTouchView
|
||||
|
||||
@end
|
|
@ -1,14 +0,0 @@
|
|||
#import "MWMSearchContentView.h"
|
||||
|
||||
@implementation MWMSearchContentView
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[self.subviews enumerateObjectsUsingBlock:^(UIView * view, NSUInteger idx, BOOL * stop)
|
||||
{
|
||||
view.frame = self.bounds;
|
||||
}];
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,8 +0,0 @@
|
|||
#import "MWMSearchManager.h"
|
||||
|
||||
@interface MWMSearchManager (Layout)
|
||||
|
||||
- (void)layoutTopViews;
|
||||
- (void)removeKeyboardObservers;
|
||||
|
||||
@end
|
|
@ -1,120 +0,0 @@
|
|||
#import <CoreApi/MWMCommon.h>
|
||||
#import "MWMSearchManager+Layout.h"
|
||||
#import "MapViewController.h"
|
||||
|
||||
static CGFloat const changeModeViewOffsetNormal = -24;
|
||||
static CGFloat const changeModeViewOffsetKeyboard = -12;
|
||||
|
||||
@interface MWMSearchManager ()
|
||||
|
||||
@property(nonatomic) IBOutlet UIView *searchBarView;
|
||||
@property(nonatomic) IBOutlet UIView *actionBarView;
|
||||
@property(nonatomic) IBOutlet UIView *contentView;
|
||||
|
||||
@property(nonatomic) NSLayoutConstraint *contentViewTopHidden;
|
||||
@property(nonatomic) NSLayoutConstraint *contentViewBottomHidden;
|
||||
@property(nonatomic) NSLayoutConstraint *actionBarViewBottomKeyboard;
|
||||
@property(nonatomic) NSLayoutConstraint *actionBarViewBottomNormal;
|
||||
|
||||
@property(weak, nonatomic, readonly) UIView *searchViewContainer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSearchManager (Layout)
|
||||
|
||||
- (void)layoutTopViews {
|
||||
UIView *searchBarView = self.searchBarView;
|
||||
UIView *changeModeView = self.actionBarView;
|
||||
UIView *contentView = self.contentView;
|
||||
UIView *parentView = self.searchViewContainer;
|
||||
|
||||
searchBarView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
changeModeView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
contentView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
|
||||
NSLayoutXAxisAnchor *leadingAnchor = parentView.leadingAnchor;
|
||||
NSLayoutXAxisAnchor *trailingAnchor = parentView.trailingAnchor;
|
||||
NSLayoutYAxisAnchor *topAnchor = parentView.safeAreaLayoutGuide.topAnchor;
|
||||
NSLayoutYAxisAnchor *bottomAnchor = parentView.safeAreaLayoutGuide.bottomAnchor;
|
||||
|
||||
[searchBarView.topAnchor constraintEqualToAnchor:topAnchor].active = YES;
|
||||
[searchBarView.leadingAnchor constraintEqualToAnchor:leadingAnchor].active = YES;
|
||||
if (IPAD)
|
||||
[searchBarView.widthAnchor constraintEqualToConstant:kWidthForiPad].active = YES;
|
||||
else
|
||||
[searchBarView.trailingAnchor constraintEqualToAnchor:trailingAnchor].active = YES;
|
||||
|
||||
[changeModeView.centerXAnchor constraintEqualToAnchor:parentView.centerXAnchor].active = YES;
|
||||
self.actionBarViewBottomNormal = [changeModeView.bottomAnchor constraintEqualToAnchor:bottomAnchor
|
||||
constant:changeModeViewOffsetNormal];
|
||||
self.actionBarViewBottomNormal.priority = UILayoutPriorityDefaultLow + 10;
|
||||
self.actionBarViewBottomNormal.active = YES;
|
||||
|
||||
self.actionBarViewBottomKeyboard = [changeModeView.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor
|
||||
constant:changeModeViewOffsetKeyboard];
|
||||
self.actionBarViewBottomKeyboard.priority = UILayoutPriorityDefaultLow;
|
||||
self.actionBarViewBottomKeyboard.active = YES;
|
||||
|
||||
NSLayoutConstraint *contentViewTop = [contentView.topAnchor constraintEqualToAnchor:searchBarView.bottomAnchor];
|
||||
contentViewTop.priority = UILayoutPriorityDefaultLow + 10;
|
||||
contentViewTop.active = YES;
|
||||
|
||||
NSLayoutConstraint *contentViewBottom = [contentView.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor];
|
||||
contentViewBottom.priority = UILayoutPriorityDefaultLow + 10;
|
||||
contentViewBottom.active = YES;
|
||||
|
||||
self.contentViewTopHidden = [contentView.topAnchor constraintEqualToAnchor:parentView.bottomAnchor];
|
||||
self.contentViewTopHidden.priority = UILayoutPriorityDefaultLow;
|
||||
self.contentViewTopHidden.active = YES;
|
||||
|
||||
self.contentViewBottomHidden = [contentView.heightAnchor constraintEqualToAnchor:parentView.heightAnchor];
|
||||
self.contentViewBottomHidden.priority = UILayoutPriorityDefaultLow;
|
||||
self.contentViewBottomHidden.active = YES;
|
||||
|
||||
[contentView.leadingAnchor constraintEqualToAnchor:searchBarView.leadingAnchor].active = YES;
|
||||
[contentView.trailingAnchor constraintEqualToAnchor:searchBarView.trailingAnchor].active = YES;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(keyboardWillShow:)
|
||||
name:UIKeyboardWillShowNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(keyboardWillHide:)
|
||||
name:UIKeyboardWillHideNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)removeKeyboardObservers {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - keyboard movements
|
||||
- (void)keyboardWillShow:(NSNotification *)notification {
|
||||
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
|
||||
CGFloat offset = IPAD ? changeModeViewOffsetNormal : changeModeViewOffsetKeyboard;
|
||||
if (self.actionBarView.isHidden) {
|
||||
self.actionBarViewBottomKeyboard.constant = -keyboardSize.height + offset;
|
||||
self.actionBarViewBottomKeyboard.priority = UILayoutPriorityDefaultHigh;
|
||||
} else {
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.actionBarViewBottomKeyboard.constant = -keyboardSize.height + offset;
|
||||
self.actionBarViewBottomKeyboard.priority = UILayoutPriorityDefaultHigh;
|
||||
[self.actionBarView.superview layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification {
|
||||
if (self.actionBarView.isHidden) {
|
||||
self.actionBarViewBottomKeyboard.priority = UILayoutPriorityDefaultLow;
|
||||
} else {
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.actionBarViewBottomKeyboard.priority = UILayoutPriorityDefaultLow;
|
||||
[self.actionBarView.superview layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,34 +0,0 @@
|
|||
#import "MWMAlertViewController.h"
|
||||
#import "MWMSearchManagerObserver.h"
|
||||
#import "MWMSearchManagerState.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, MWMSearchManagerRoutingTooltipSearch) {
|
||||
MWMSearchManagerRoutingTooltipSearchNone,
|
||||
MWMSearchManagerRoutingTooltipSearchStart,
|
||||
MWMSearchManagerRoutingTooltipSearchFinish
|
||||
};
|
||||
@class SearchTextField;
|
||||
|
||||
@interface MWMSearchManager : NSObject
|
||||
|
||||
extern const CGFloat kWidthForiPad;
|
||||
|
||||
+ (nonnull MWMSearchManager *)manager NS_SWIFT_NAME(manager());
|
||||
+ (void)addObserver:(nonnull id<MWMSearchManagerObserver>)observer;
|
||||
+ (void)removeObserver:(nonnull id<MWMSearchManagerObserver>)observer;
|
||||
|
||||
@property(nullable, weak, nonatomic) IBOutlet SearchTextField *searchTextField;
|
||||
|
||||
@property(nonatomic) MWMSearchManagerState state;
|
||||
@property(nonatomic) MWMSearchManagerRoutingTooltipSearch routingTooltipSearch;
|
||||
|
||||
@property(nonnull, nonatomic) IBOutletCollection(UIView) NSArray *topViews;
|
||||
|
||||
- (void)searchText:(nonnull NSString *)text forInputLocale:(nullable NSString *)locale withCategory:(BOOL)isCategory;
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(nonnull id<UIViewControllerTransitionCoordinator>)coordinator;
|
||||
|
||||
@end
|
|
@ -1,538 +0,0 @@
|
|||
#import "MWMSearchManager.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMNoMapsViewController.h"
|
||||
#import "MWMRoutePoint+CPP.h"
|
||||
#import "MWMRouter.h"
|
||||
#import "MWMSearchManager+Layout.h"
|
||||
#import "MWMSearchTableViewController.h"
|
||||
#import "MapViewController.h"
|
||||
#import "SearchResult.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
namespace {
|
||||
typedef NS_ENUM(NSUInteger, MWMSearchManagerActionBarState) {
|
||||
MWMSearchManagerActionBarStateHidden,
|
||||
MWMSearchManagerActionBarStateTabBar,
|
||||
MWMSearchManagerActionBarStateModeFilter
|
||||
};
|
||||
|
||||
using Observer = id<MWMSearchManagerObserver>;
|
||||
using Observers = NSHashTable<Observer>;
|
||||
} // namespace
|
||||
|
||||
const CGFloat kWidthForiPad = 320;
|
||||
|
||||
@interface MWMMapViewControlsManager ()
|
||||
|
||||
@property(nonatomic) MWMSearchManager *searchManager;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMSearchManager () <MWMSearchTableViewProtocol,
|
||||
MWMSearchTabViewControllerDelegate,
|
||||
UITextFieldDelegate,
|
||||
MWMStorageObserver,
|
||||
MWMSearchObserver>
|
||||
|
||||
@property(weak, nonatomic, readonly) UIViewController *ownerController;
|
||||
@property(weak, nonatomic, readonly) UIView *searchViewContainer;
|
||||
@property(weak, nonatomic, readonly) UIView *actionBarContainer;
|
||||
@property(weak, nonatomic, readonly) MWMMapViewControlsManager *controlsManager;
|
||||
|
||||
@property(nonatomic) IBOutlet SearchBar *searchBarView;
|
||||
@property(weak, nonatomic) IBOutlet SearchActionBarView *actionBarView;
|
||||
@property(nonatomic) IBOutlet UIView *contentView;
|
||||
@property(strong, nonatomic) IBOutlet UIView *tableViewContainer;
|
||||
|
||||
@property(nonatomic) NSLayoutConstraint *contentViewTopHidden;
|
||||
@property(nonatomic) NSLayoutConstraint *contentViewBottomHidden;
|
||||
@property(nonatomic) NSLayoutConstraint *actionBarViewBottomKeyboard;
|
||||
@property(nonatomic) NSLayoutConstraint *actionBarViewBottomNormal;
|
||||
|
||||
@property(nonatomic) UINavigationController *navigationController;
|
||||
@property(nonatomic) MWMSearchTableViewController *tableViewController;
|
||||
@property(nonatomic) MWMNoMapsViewController *noMapsController;
|
||||
|
||||
@property(nonatomic) Observers *observers;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSearchManager
|
||||
|
||||
+ (MWMSearchManager *)manager {
|
||||
return [MWMMapViewControlsManager manager].searchManager;
|
||||
}
|
||||
- (nullable instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[NSBundle.mainBundle loadNibNamed:@"MWMSearchView" owner:self options:nil];
|
||||
self.state = MWMSearchManagerStateHidden;
|
||||
[MWMSearch addObserver:self];
|
||||
_observers = [Observers weakObjectsHashTable];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)beginSearch {
|
||||
if (self.state != MWMSearchManagerStateHidden)
|
||||
self.state = MWMSearchManagerStateTableSearch;
|
||||
}
|
||||
|
||||
- (void)endSearch {
|
||||
if (self.state != MWMSearchManagerStateHidden)
|
||||
self.state = MWMSearchManagerStateDefault;
|
||||
self.searchTextField.text = @"";
|
||||
[MWMSearch clear];
|
||||
}
|
||||
|
||||
- (void)closeSearch {
|
||||
[self.searchTextField endEditing:YES];
|
||||
[self endSearch];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)textFieldDidEndEditing:(UITextField *)textField {
|
||||
if (textField.text.length == 0)
|
||||
[self endSearch];
|
||||
}
|
||||
|
||||
- (IBAction)textFieldTextDidChange:(UITextField *)textField {
|
||||
NSString *text = textField.text;
|
||||
if (text.length > 0) {
|
||||
[self beginSearch];
|
||||
[MWMSearch searchQuery:text forInputLocale:textField.textInputMode.primaryLanguage withCategory:NO];
|
||||
} else {
|
||||
[self endSearch];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)cancelButtonPressed {
|
||||
self.state = MWMSearchManagerStateHidden;
|
||||
}
|
||||
|
||||
- (IBAction)backButtonPressed {
|
||||
self.state = MWMSearchManagerStateTableSearch;
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[self.navigationController viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (void)textFieldDidBeginEditing:(UITextField *)textField {
|
||||
BOOL const isEmpty = (textField.text.length == 0);
|
||||
self.state = isEmpty ? MWMSearchManagerStateDefault : MWMSearchManagerStateTableSearch;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
textField.text = [[textField.text stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet]
|
||||
stringByAppendingString:@" "];
|
||||
[self textFieldTextDidChange:textField];
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchTabbedViewProtocol
|
||||
|
||||
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale withCategory:(BOOL)isCategory {
|
||||
[self beginSearch];
|
||||
self.searchTextField.text = text;
|
||||
NSString *inputLocale = locale ?: self.searchTextField.textInputMode.primaryLanguage;
|
||||
[MWMSearch searchQuery:text forInputLocale:inputLocale withCategory:isCategory];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[self.searchTextField resignFirstResponder];
|
||||
}
|
||||
- (void)processSearchResultAtIndex:(NSInteger)index {
|
||||
if (self.routingTooltipSearch == MWMSearchManagerRoutingTooltipSearchNone) {
|
||||
[MWMSearch showResultAtIndex:index];
|
||||
} else {
|
||||
BOOL const isStart = self.routingTooltipSearch == MWMSearchManagerRoutingTooltipSearchStart;
|
||||
SearchResult * result = [MWMSearch resultWithContainerIndex:index];
|
||||
auto point = [[MWMRoutePoint alloc] initWithCGPoint:result.point
|
||||
title:result.titleText
|
||||
subtitle:result.addressText
|
||||
type:isStart ? MWMRoutePointTypeStart : MWMRoutePointTypeFinish
|
||||
intermediateIndex:0];
|
||||
if (isStart)
|
||||
[MWMRouter buildFromPoint:point bestRouter:NO];
|
||||
else
|
||||
[MWMRouter buildToPoint:point bestRouter:NO];
|
||||
}
|
||||
if (!IPAD || [MWMNavigationDashboardManager sharedManager].state != MWMNavigationDashboardStateHidden)
|
||||
self.state = MWMSearchManagerStateResult;
|
||||
}
|
||||
|
||||
#pragma mark - MWMStorageObserver
|
||||
|
||||
- (void)processCountryEvent:(NSString *)countryId {
|
||||
using namespace storage;
|
||||
NodeStatuses nodeStatuses{};
|
||||
GetFramework().GetStorage().GetNodeStatuses(countryId.UTF8String, nodeStatuses);
|
||||
if (nodeStatuses.m_status != NodeStatus::OnDisk)
|
||||
return;
|
||||
[self updateTopController];
|
||||
if (self.state == MWMSearchManagerStateTableSearch || self.state == MWMSearchManagerStateMapSearch) {
|
||||
NSString *text = self.searchTextField.text;
|
||||
if (text.length != 0)
|
||||
[MWMSearch searchQuery:text forInputLocale:self.searchTextField.textInputMode.primaryLanguage withCategory:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - State changes
|
||||
|
||||
- (void)updateTopController {
|
||||
UIViewController *selfTopVC = self.topController;
|
||||
if (!selfTopVC || [selfTopVC isEqual:self.navigationController.topViewController])
|
||||
return;
|
||||
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
|
||||
viewControllers[0] = selfTopVC;
|
||||
[self.navigationController setViewControllers:viewControllers animated:NO];
|
||||
}
|
||||
|
||||
- (void)changeToHiddenState {
|
||||
self.routingTooltipSearch = MWMSearchManagerRoutingTooltipSearchNone;
|
||||
[self closeSearch];
|
||||
|
||||
MWMMapViewControlsManager *controlsManager = self.controlsManager;
|
||||
auto const navigationManagerState = [MWMNavigationDashboardManager sharedManager].state;
|
||||
if (navigationManagerState == MWMNavigationDashboardStateHidden) {
|
||||
controlsManager.menuState = controlsManager.menuRestoreState;
|
||||
}
|
||||
[self viewHidden:YES];
|
||||
}
|
||||
|
||||
- (void)changeToDefaultState {
|
||||
MWMMapViewControlsManager *controlsManager = self.controlsManager;
|
||||
|
||||
[self.navigationController popToRootViewControllerAnimated:NO];
|
||||
|
||||
self.searchBarView.state = SearchBarStateReady;
|
||||
GetFramework().DeactivateMapSelection();
|
||||
[self animateConstraints:^{
|
||||
self.contentViewTopHidden.priority = UILayoutPriorityDefaultLow;
|
||||
self.contentViewBottomHidden.priority = UILayoutPriorityDefaultLow;
|
||||
}];
|
||||
auto const navigationManagerState = [MWMNavigationDashboardManager sharedManager].state;
|
||||
if (navigationManagerState == MWMNavigationDashboardStateHidden) {
|
||||
controlsManager.menuState = controlsManager.menuRestoreState;
|
||||
}
|
||||
[self viewHidden:NO];
|
||||
self.actionBarState = MWMSearchManagerActionBarStateHidden;
|
||||
[self.searchTextField becomeFirstResponder];
|
||||
[self.searchBarView applyTheme];
|
||||
}
|
||||
|
||||
- (void)changeToTableSearchState {
|
||||
MWMMapViewControlsManager *controlsManager = self.controlsManager;
|
||||
|
||||
[self.navigationController popToRootViewControllerAnimated:NO];
|
||||
|
||||
self.searchBarView.state = SearchBarStateReady;
|
||||
GetFramework().DeactivateMapSelection();
|
||||
[self updateTableSearchActionBar];
|
||||
auto const navigationManagerState = [MWMNavigationDashboardManager sharedManager].state;
|
||||
if (navigationManagerState == MWMNavigationDashboardStateHidden) {
|
||||
controlsManager.menuState = controlsManager.menuRestoreState;
|
||||
}
|
||||
[self viewHidden:NO];
|
||||
[MWMSearch setSearchOnMap:NO];
|
||||
[self.tableViewController reloadData];
|
||||
|
||||
if (![self.navigationController.viewControllers containsObject:self.tableViewController])
|
||||
[self.navigationController pushViewController:self.tableViewController animated:NO];
|
||||
}
|
||||
|
||||
- (void)changeToMapSearchState {
|
||||
[self.navigationController popToRootViewControllerAnimated:NO];
|
||||
|
||||
self.searchBarView.state = SearchBarStateBack;
|
||||
self.actionBarState = MWMSearchManagerActionBarStateModeFilter;
|
||||
if (!IPAD) {
|
||||
[self animateConstraints:^{
|
||||
self.contentViewTopHidden.priority = UILayoutPriorityDefaultHigh;
|
||||
self.contentViewBottomHidden.priority = UILayoutPriorityDefaultHigh;
|
||||
}];
|
||||
}
|
||||
auto const navigationManagerState = [MWMNavigationDashboardManager sharedManager].state;
|
||||
[self viewHidden:navigationManagerState != MWMNavigationDashboardStateHidden];
|
||||
self.controlsManager.menuState = MWMBottomMenuStateHidden;
|
||||
GetFramework().DeactivateMapSelection();
|
||||
[MWMSearch setSearchOnMap:YES];
|
||||
[self.tableViewController reloadData];
|
||||
|
||||
[self.searchTextField resignFirstResponder];
|
||||
|
||||
if (navigationManagerState == MWMNavigationDashboardStateNavigation) {
|
||||
self.searchTextField.text = @"";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changeToResultSearchState {
|
||||
[self.navigationController popToRootViewControllerAnimated:NO];
|
||||
|
||||
self.searchBarView.state = SearchBarStateBack;
|
||||
self.actionBarState = MWMSearchManagerActionBarStateModeFilter;
|
||||
if (!IPAD) {
|
||||
[self animateConstraints:^{
|
||||
self.contentViewTopHidden.priority = UILayoutPriorityDefaultHigh;
|
||||
self.contentViewBottomHidden.priority = UILayoutPriorityDefaultHigh;
|
||||
|
||||
}];
|
||||
}
|
||||
auto const navigationManagerState = [MWMNavigationDashboardManager sharedManager].state;
|
||||
[self viewHidden:navigationManagerState != MWMNavigationDashboardStateHidden];
|
||||
[self.tableViewController reloadData];
|
||||
|
||||
[self.searchTextField resignFirstResponder];
|
||||
|
||||
if (navigationManagerState == MWMNavigationDashboardStateNavigation) {
|
||||
self.searchTextField.text = @"";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)animateConstraints:(MWMVoidBlock)block {
|
||||
UIView *parentView = self.searchViewContainer;
|
||||
[parentView layoutIfNeeded];
|
||||
block();
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
[parentView layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchObserver
|
||||
|
||||
- (void)onSearchCompleted {
|
||||
if (self.state == MWMSearchManagerStateMapSearch || self.state == MWMSearchManagerStateResult) {
|
||||
self.searchBarView.state = SearchBarStateBack;
|
||||
} else {
|
||||
self.searchBarView.state = SearchBarStateReady;
|
||||
}
|
||||
|
||||
if (self.state != MWMSearchManagerStateTableSearch)
|
||||
return;
|
||||
[self.tableViewController onSearchCompleted];
|
||||
[self updateTableSearchActionBar];
|
||||
}
|
||||
|
||||
- (void)onSearchStarted {
|
||||
self.searchBarView.state = SearchBarStateSearching;
|
||||
if (self.state != MWMSearchManagerStateTableSearch)
|
||||
return;
|
||||
self.actionBarState = MWMSearchManagerActionBarStateModeFilter;
|
||||
}
|
||||
|
||||
- (void)onSearchResultsUpdated {
|
||||
[self.tableViewController reloadData];
|
||||
}
|
||||
|
||||
- (void)updateTableSearchActionBar {
|
||||
if (self.state != MWMSearchManagerStateTableSearch)
|
||||
return;
|
||||
[self animateConstraints:^{
|
||||
BOOL hideActionBar = NO;
|
||||
if ([MWMSearch resultsCount] == 0)
|
||||
hideActionBar = YES;
|
||||
else if (IPAD)
|
||||
hideActionBar = YES;
|
||||
self.actionBarState =
|
||||
hideActionBar ? MWMSearchManagerActionBarStateHidden : MWMSearchManagerActionBarStateModeFilter;
|
||||
|
||||
self.contentViewTopHidden.priority = UILayoutPriorityDefaultLow;
|
||||
self.contentViewBottomHidden.priority = UILayoutPriorityDefaultLow;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Add/Remove Observers
|
||||
|
||||
+ (void)addObserver:(id<MWMSearchManagerObserver>)observer {
|
||||
[[MWMSearchManager manager].observers addObject:observer];
|
||||
}
|
||||
|
||||
+ (void)removeObserver:(id<MWMSearchManagerObserver>)observer {
|
||||
[[MWMSearchManager manager].observers removeObject:observer];
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchManagerObserver
|
||||
|
||||
- (void)onSearchManagerStateChanged {
|
||||
for (Observer observer in self.observers)
|
||||
[observer onSearchManagerStateChanged];
|
||||
}
|
||||
|
||||
#pragma mark - Filters
|
||||
|
||||
- (IBAction)changeMode {
|
||||
switch (self.state) {
|
||||
case MWMSearchManagerStateTableSearch:
|
||||
self.state = MWMSearchManagerStateMapSearch;
|
||||
break;
|
||||
case MWMSearchManagerStateMapSearch:
|
||||
self.state = MWMSearchManagerStateTableSearch;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (UINavigationController *)navigationController {
|
||||
if (!_navigationController) {
|
||||
_navigationController = [[UINavigationController alloc] init];
|
||||
[self.contentView addSubview:_navigationController.view];
|
||||
_navigationController.navigationBarHidden = YES;
|
||||
}
|
||||
return _navigationController;
|
||||
}
|
||||
|
||||
- (UIViewController *)topController {
|
||||
[[MWMStorage sharedStorage] removeObserver:self];
|
||||
self.noMapsController = nil;
|
||||
switch (self.state) {
|
||||
case MWMSearchManagerStateHidden:
|
||||
return nil;
|
||||
case MWMSearchManagerStateDefault: {
|
||||
if (GetFramework().GetStorage().HaveDownloadedCountries()) {
|
||||
MWMSearchTabViewController *tabViewController = [MWMSearchTabViewController new];
|
||||
tabViewController.delegate = self;
|
||||
return tabViewController;
|
||||
}
|
||||
self.noMapsController = [MWMNoMapsViewController controller];
|
||||
[[MWMStorage sharedStorage] addObserver:self];
|
||||
return self.noMapsController;
|
||||
}
|
||||
case MWMSearchManagerStateTableSearch:
|
||||
return self.tableViewController;
|
||||
case MWMSearchManagerStateMapSearch:
|
||||
return self.tableViewController;
|
||||
case MWMSearchManagerStateResult:
|
||||
return self.tableViewController;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchTabController:(MWMSearchTabViewController *)viewController
|
||||
didSearch:(NSString *)didSearch
|
||||
withCategory:(BOOL)isCategory
|
||||
{
|
||||
[self searchText:didSearch forInputLocale:[[AppInfo sharedInfo] languageId] withCategory:isCategory];
|
||||
}
|
||||
|
||||
- (MWMSearchTableViewController *)tableViewController {
|
||||
if (!_tableViewController)
|
||||
_tableViewController = [[MWMSearchTableViewController alloc] initWithDelegate:self];
|
||||
return _tableViewController;
|
||||
}
|
||||
|
||||
- (void)setState:(MWMSearchManagerState)state {
|
||||
if (_state == state)
|
||||
return;
|
||||
|
||||
_state = state;
|
||||
[self updateTopController];
|
||||
switch (state) {
|
||||
case MWMSearchManagerStateHidden:
|
||||
[self changeToHiddenState];
|
||||
break;
|
||||
case MWMSearchManagerStateDefault:
|
||||
[self changeToDefaultState];
|
||||
break;
|
||||
case MWMSearchManagerStateTableSearch:
|
||||
[self changeToTableSearchState];
|
||||
break;
|
||||
case MWMSearchManagerStateMapSearch:
|
||||
[self changeToMapSearchState];
|
||||
break;
|
||||
case MWMSearchManagerStateResult:
|
||||
[self changeToResultSearchState];
|
||||
break;
|
||||
}
|
||||
[self onSearchManagerStateChanged];
|
||||
[self.actionBarView updateForState:state];
|
||||
[[MapViewController sharedController] updateStatusBarStyle];
|
||||
}
|
||||
|
||||
- (void)viewHidden:(BOOL)hidden {
|
||||
UIView *searchBarView = self.searchBarView;
|
||||
UIView *actionBarView = self.actionBarView;
|
||||
UIView *contentView = self.contentView;
|
||||
UIView *parentView = self.searchViewContainer;
|
||||
|
||||
if (!hidden) {
|
||||
if (searchBarView.superview) {
|
||||
[parentView bringSubviewToFront:searchBarView];
|
||||
[parentView bringSubviewToFront:contentView];
|
||||
[parentView bringSubviewToFront:actionBarView];
|
||||
return;
|
||||
}
|
||||
[parentView addSubview:searchBarView];
|
||||
[parentView addSubview:contentView];
|
||||
[parentView addSubview:actionBarView];
|
||||
[self layoutTopViews];
|
||||
// Set Search controller default hidden state for iPad before it will be shown.
|
||||
if (IPAD) {
|
||||
self.searchViewContainerLeadingConstraint.constant = -kWidthForiPad;
|
||||
[parentView.superview layoutIfNeeded];
|
||||
}
|
||||
}
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
if (IPAD) {
|
||||
self.searchViewContainerLeadingConstraint.constant = hidden ? -kWidthForiPad : 0;
|
||||
[parentView.superview layoutIfNeeded];
|
||||
} else {
|
||||
CGFloat const alpha = hidden ? 0 : 1;
|
||||
contentView.alpha = alpha;
|
||||
actionBarView.alpha = alpha;
|
||||
searchBarView.alpha = alpha;
|
||||
}
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
if (!hidden)
|
||||
return;
|
||||
[contentView removeFromSuperview];
|
||||
[actionBarView removeFromSuperview];
|
||||
[searchBarView removeFromSuperview];
|
||||
[self removeKeyboardObservers];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setActionBarState:(MWMSearchManagerActionBarState)actionBarState {
|
||||
switch (actionBarState) {
|
||||
case MWMSearchManagerActionBarStateHidden:
|
||||
self.actionBarView.hidden = YES;
|
||||
break;
|
||||
case MWMSearchManagerActionBarStateTabBar:
|
||||
self.actionBarView.hidden = YES;
|
||||
break;
|
||||
case MWMSearchManagerActionBarStateModeFilter:
|
||||
self.actionBarView.hidden = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIViewController *)ownerController {
|
||||
return [MapViewController sharedController];
|
||||
}
|
||||
- (UIView *)searchViewContainer {
|
||||
return [MapViewController sharedController].searchViewContainer;
|
||||
}
|
||||
- (NSLayoutConstraint *)searchViewContainerLeadingConstraint {
|
||||
return [MapViewController sharedController].searchViewContainerLeadingConstraint;
|
||||
}
|
||||
- (UIView *)actionBarContainer {
|
||||
return [MapViewController sharedController].controlsView;
|
||||
}
|
||||
|
||||
- (MWMMapViewControlsManager *)controlsManager {
|
||||
return [MWMMapViewControlsManager manager];
|
||||
}
|
||||
@end
|
|
@ -1,5 +0,0 @@
|
|||
@protocol MWMSearchManagerObserver<NSObject>
|
||||
|
||||
- (void)onSearchManagerStateChanged;
|
||||
|
||||
@end
|
|
@ -1,8 +0,0 @@
|
|||
typedef NS_ENUM(NSUInteger, MWMSearchManagerState)
|
||||
{
|
||||
MWMSearchManagerStateHidden,
|
||||
MWMSearchManagerStateDefault,
|
||||
MWMSearchManagerStateTableSearch,
|
||||
MWMSearchManagerStateMapSearch,
|
||||
MWMSearchManagerStateResult
|
||||
};
|
|
@ -1,266 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMSearchManager">
|
||||
<connections>
|
||||
<outlet property="actionBarView" destination="d2A-Id-T62" id="UKk-U2-Mwl"/>
|
||||
<outlet property="contentView" destination="u9y-bx-NGd" id="A03-AI-DbY"/>
|
||||
<outlet property="searchBarView" destination="g9f-m8-RFv" id="opS-Ll-3Fn"/>
|
||||
<outlet property="searchTextField" destination="ySb-oA-ZeW" id="Awu-Z4-EdK"/>
|
||||
<outlet property="tableViewContainer" destination="QQn-4W-Y0s" id="5hb-b3-y8Q"/>
|
||||
<outletCollection property="topViews" destination="u9y-bx-NGd" id="mAw-CD-QQV"/>
|
||||
<outletCollection property="topViews" destination="d2A-Id-T62" id="Q0C-Eb-VyX"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g9f-m8-RFv" customClass="SearchBar" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="88"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C73-2V-To8" userLabel="StatusBarBackground">
|
||||
<rect key="frame" x="0.0" y="-100" width="320" height="188"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchBarView"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<stackView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="DrM-QJ-TCl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="88"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ghc-B6-erG">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="88"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="fill" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" adjustsFontSizeToFit="NO" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="ySb-oA-ZeW" userLabel="Search" customClass="SearchTextField" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="16" y="8" width="232" height="72"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="queryField"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="search"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchSearchTextField"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedPlaceholder" value="search"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="textFieldDidEndEditing:" destination="-1" eventType="editingDidEnd" id="CuD-rP-0bT"/>
|
||||
<action selector="textFieldTextDidChange:" destination="-1" eventType="editingChanged" id="NU4-jh-Dd4"/>
|
||||
<outlet property="delegate" destination="-1" id="U2Z-lL-bo1"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="wordWrap" translatesAutoresizingMaskIntoConstraints="NO" id="qkR-cN-NI4">
|
||||
<rect key="frame" x="248" y="4" width="72" height="80"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="cancelButton"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="72" id="8mI-K9-qAu"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<inset key="contentEdgeInsets" minX="4" minY="0.0" maxX="4" maxY="0.0"/>
|
||||
<state key="normal" title="Cancel">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="cancel"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="whitePrimaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="cancelButtonPressed" destination="-1" eventType="touchUpInside" id="cx8-zT-fgZ"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_search" translatesAutoresizingMaskIntoConstraints="NO" id="ebE-7b-E9f">
|
||||
<rect key="frame" x="16" y="8" width="36" height="72"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="36" id="8Ta-mE-6dI"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchSearchTextFieldIcon"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="pnj-0S-fkE">
|
||||
<rect key="frame" x="16" y="8" width="36" height="72"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="36" id="v0W-Aw-eSV"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchSearchTextFieldIcon"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</activityIndicatorView>
|
||||
<button opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CrZ-Cz-xyW">
|
||||
<rect key="frame" x="16" y="8" width="36" height="72"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="36" id="gfO-3m-OFv"/>
|
||||
</constraints>
|
||||
<state key="normal" image="ic_search_back"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchSearchTextFieldIcon"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="backButtonPressed" destination="-1" eventType="touchUpInside" id="xyJ-fc-ged"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="pnj-0S-fkE" firstAttribute="top" secondItem="ySb-oA-ZeW" secondAttribute="top" id="4oA-1o-TMf"/>
|
||||
<constraint firstItem="qkR-cN-NI4" firstAttribute="top" secondItem="ghc-B6-erG" secondAttribute="top" constant="4" id="FlS-h1-5Su"/>
|
||||
<constraint firstItem="qkR-cN-NI4" firstAttribute="leading" secondItem="ySb-oA-ZeW" secondAttribute="trailing" id="HJ2-r6-yVw"/>
|
||||
<constraint firstItem="ebE-7b-E9f" firstAttribute="bottom" secondItem="ySb-oA-ZeW" secondAttribute="bottom" id="R45-81-QPe"/>
|
||||
<constraint firstItem="ebE-7b-E9f" firstAttribute="leading" secondItem="ySb-oA-ZeW" secondAttribute="leading" id="THA-Pu-i5t"/>
|
||||
<constraint firstItem="CrZ-Cz-xyW" firstAttribute="top" secondItem="ySb-oA-ZeW" secondAttribute="top" id="WxT-Hy-CL1"/>
|
||||
<constraint firstItem="CrZ-Cz-xyW" firstAttribute="bottom" secondItem="ySb-oA-ZeW" secondAttribute="bottom" id="XIJ-EQ-sfC"/>
|
||||
<constraint firstAttribute="height" constant="52" id="evQ-q0-G3V"/>
|
||||
<constraint firstAttribute="bottom" secondItem="qkR-cN-NI4" secondAttribute="bottom" constant="8" id="exK-0S-ML2"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ySb-oA-ZeW" secondAttribute="bottom" constant="8" id="kc1-xj-dnr"/>
|
||||
<constraint firstItem="ySb-oA-ZeW" firstAttribute="leading" secondItem="ghc-B6-erG" secondAttribute="leading" constant="16" id="kch-1z-rhZ"/>
|
||||
<constraint firstItem="CrZ-Cz-xyW" firstAttribute="leading" secondItem="ySb-oA-ZeW" secondAttribute="leading" id="m7Z-jP-Upg"/>
|
||||
<constraint firstAttribute="trailing" secondItem="qkR-cN-NI4" secondAttribute="trailing" id="ngR-ML-Cnj"/>
|
||||
<constraint firstItem="pnj-0S-fkE" firstAttribute="leading" secondItem="ySb-oA-ZeW" secondAttribute="leading" id="ove-r5-YFo"/>
|
||||
<constraint firstItem="qkR-cN-NI4" firstAttribute="centerY" secondItem="ySb-oA-ZeW" secondAttribute="centerY" id="rPK-s8-GJi"/>
|
||||
<constraint firstItem="pnj-0S-fkE" firstAttribute="bottom" secondItem="ySb-oA-ZeW" secondAttribute="bottom" id="udX-a7-hOd"/>
|
||||
<constraint firstItem="ySb-oA-ZeW" firstAttribute="top" secondItem="ghc-B6-erG" secondAttribute="top" constant="8" id="yet-nD-qWN"/>
|
||||
<constraint firstItem="ebE-7b-E9f" firstAttribute="top" secondItem="ySb-oA-ZeW" secondAttribute="top" id="zqb-O1-mO9"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="VX9-29-j2Z"/>
|
||||
<color key="backgroundColor" red="0.12549019610000001" green="0.59607843140000005" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="C73-2V-To8" firstAttribute="top" secondItem="g9f-m8-RFv" secondAttribute="top" constant="-100" id="Alh-jk-902"/>
|
||||
<constraint firstItem="DrM-QJ-TCl" firstAttribute="leading" secondItem="g9f-m8-RFv" secondAttribute="leading" id="Fqj-iv-GAo"/>
|
||||
<constraint firstAttribute="bottom" secondItem="DrM-QJ-TCl" secondAttribute="bottom" id="Wtv-8F-BmX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="C73-2V-To8" secondAttribute="bottom" id="e6z-lu-FFZ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="DrM-QJ-TCl" secondAttribute="trailing" id="eSZ-Cp-LJl"/>
|
||||
<constraint firstAttribute="width" secondItem="DrM-QJ-TCl" secondAttribute="width" id="he4-ZG-kIs"/>
|
||||
<constraint firstItem="C73-2V-To8" firstAttribute="leading" secondItem="g9f-m8-RFv" secondAttribute="leading" id="qhr-if-gM8">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="trailing" secondItem="C73-2V-To8" secondAttribute="trailing" id="xV9-by-bNe">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstItem="DrM-QJ-TCl" firstAttribute="top" secondItem="g9f-m8-RFv" secondAttribute="top" id="zwx-cA-Bru"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchBar"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="pnj-0S-fkE" id="fLT-4I-s5b"/>
|
||||
<outlet property="backButton" destination="CrZ-Cz-xyW" id="fIz-hG-JFM"/>
|
||||
<outlet property="searchIcon" destination="ebE-7b-E9f" id="sCN-KI-2a1"/>
|
||||
<outlet property="searchTextField" destination="ySb-oA-ZeW" id="xHR-vF-csP"/>
|
||||
<outlet property="stackView" destination="DrM-QJ-TCl" id="Fzm-8G-JnZ"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="225.59999999999999" y="-211.39430284857573"/>
|
||||
</view>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="d2A-Id-T62" customClass="SearchActionBarView" customModule="Organic_Maps" customModuleProvider="target" propertyAccessControl="none">
|
||||
<rect key="frame" x="0.0" y="0.0" width="361" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2gF-Kc-0a7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="361" height="36"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a8x-P8-Y8p" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="296" height="36"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="viewOnMapButton"/>
|
||||
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
|
||||
<state key="normal" title="Map" image="ic_search_mode_map"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchActionBarButton"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="search_show_on_map"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="changeMode" destination="-1" eventType="touchUpInside" id="uAW-Mp-BVp"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Enq-yv-2XZ" customClass="MWMButton">
|
||||
<rect key="frame" x="296" y="0.0" width="65" height="36"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="viewOnMapButton"/>
|
||||
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
|
||||
<state key="normal" title="List" image="ic_search_mode_list"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchActionBarButton"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="search_in_table"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="changeMode" destination="-1" eventType="touchUpInside" id="yqV-vF-c3I"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Bgt-hj-RpB"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="2gF-Kc-0a7" secondAttribute="trailing" id="Fdx-hX-coi"/>
|
||||
<constraint firstItem="2gF-Kc-0a7" firstAttribute="top" secondItem="d2A-Id-T62" secondAttribute="top" id="Y62-Rf-LAh"/>
|
||||
<constraint firstAttribute="height" constant="40" id="eLk-al-10m"/>
|
||||
<constraint firstItem="2gF-Kc-0a7" firstAttribute="leading" secondItem="d2A-Id-T62" secondAttribute="leading" id="itE-d4-hzw"/>
|
||||
<constraint firstAttribute="bottom" secondItem="2gF-Kc-0a7" secondAttribute="bottom" id="s4H-Jq-xk9"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="SearchActionBarView"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="listButton" destination="Enq-yv-2XZ" id="DUY-wh-ohq"/>
|
||||
<outlet property="mapButton" destination="a8x-P8-Y8p" id="Rtu-DA-x6c"/>
|
||||
<outlet property="stackView" destination="2gF-Kc-0a7" id="08D-2t-Cpt"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="193" y="-58"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="u9y-bx-NGd" userLabel="Content" customClass="MWMSearchContentView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="402"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jHn-5d-yXG" customClass="SolidTouchView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="402"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QQn-4W-Y0s">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="368"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="wvK-7O-o3d"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="jHn-5d-yXG" firstAttribute="leading" secondItem="u9y-bx-NGd" secondAttribute="leading" id="1Qk-kN-iT5">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstItem="wvK-7O-o3d" firstAttribute="bottom" secondItem="QQn-4W-Y0s" secondAttribute="bottom" id="5UL-RM-PTF"/>
|
||||
<constraint firstItem="jHn-5d-yXG" firstAttribute="top" secondItem="u9y-bx-NGd" secondAttribute="top" id="Bgm-2G-pSD"/>
|
||||
<constraint firstItem="QQn-4W-Y0s" firstAttribute="leading" secondItem="u9y-bx-NGd" secondAttribute="leading" id="CFW-pd-Qj7"/>
|
||||
<constraint firstItem="QQn-4W-Y0s" firstAttribute="top" secondItem="u9y-bx-NGd" secondAttribute="top" id="T8W-hj-ces"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jHn-5d-yXG" secondAttribute="trailing" id="aKt-MM-Csi">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="bottom" secondItem="jHn-5d-yXG" secondAttribute="bottom" id="hm3-xK-oys">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="0.0"/>
|
||||
</constraint>
|
||||
<constraint firstAttribute="trailing" secondItem="QQn-4W-Y0s" secondAttribute="trailing" id="pBX-G3-gBz"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<point key="canvasLocation" x="236" y="229"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="ic_search" width="28" height="28"/>
|
||||
<image name="ic_search_back" width="24" height="24"/>
|
||||
<image name="ic_search_mode_list" width="20" height="20"/>
|
||||
<image name="ic_search_mode_map" width="20" height="20"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -1,56 +0,0 @@
|
|||
@objc class SearchActionBarView: SolidTouchView {
|
||||
@IBOutlet private var mapButton: MWMButton!
|
||||
@IBOutlet private var listButton: MWMButton!
|
||||
|
||||
@IBOutlet private var stackView: UIStackView!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
hideView(mapButton, isHidden: true, animated: false)
|
||||
hideView(listButton, isHidden: true, animated: false)
|
||||
}
|
||||
|
||||
@objc func updateForState(_ state: MWMSearchManagerState) {
|
||||
hideView(mapButton, isHidden: true, animated: false)
|
||||
hideView(listButton, isHidden: true, animated: false)
|
||||
|
||||
iPhoneSpecific {
|
||||
switch state {
|
||||
case .tableSearch:
|
||||
hideView(mapButton, isHidden: false, animated: true)
|
||||
case .mapSearch:
|
||||
hideView(listButton, isHidden: false, animated: true)
|
||||
case .default:
|
||||
break
|
||||
case .hidden: fallthrough
|
||||
case .result: fallthrough
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func hideView(_ view: UIView, isHidden: Bool, animated: Bool) {
|
||||
view.isHidden = isHidden
|
||||
if animated {
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration / 2,
|
||||
delay: 0,
|
||||
options: [.beginFromCurrentState],
|
||||
animations: {
|
||||
self.layoutIfNeeded()
|
||||
}, completion: { complete in
|
||||
if complete {
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration / 2,
|
||||
delay: 0, options: [.beginFromCurrentState],
|
||||
animations: {
|
||||
view.alpha = isHidden ? 0 : 1
|
||||
}, completion: nil)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
view.alpha = isHidden ? 0 : 1
|
||||
view.isHidden = isHidden
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
@objc enum SearchBarState: Int {
|
||||
case ready
|
||||
case searching
|
||||
case back
|
||||
}
|
||||
|
||||
final class SearchBar: SolidTouchView {
|
||||
@IBOutlet private var searchIcon: UIImageView!
|
||||
@IBOutlet private var activityIndicator: UIActivityIndicatorView!
|
||||
@IBOutlet private var backButton: UIButton!
|
||||
@IBOutlet private var searchTextField: SearchTextField!
|
||||
@IBOutlet private var stackView: UIStackView!
|
||||
|
||||
override var visibleAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: .top, iPad: .left) }
|
||||
|
||||
override var placePageAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: [], iPad: .left) }
|
||||
|
||||
override var widgetsAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: [], iPad: .left) }
|
||||
|
||||
override var trafficButtonAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: .top, iPad: .left) }
|
||||
|
||||
override var tabBarAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: [], iPad: .left) }
|
||||
|
||||
override var trackRecordingButtonAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: .top, iPad: .left) }
|
||||
|
||||
@objc var state: SearchBarState = .ready {
|
||||
didSet {
|
||||
if state != oldValue {
|
||||
updateLeftView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
updateLeftView()
|
||||
searchTextField.leftViewMode = UITextField.ViewMode.always
|
||||
searchTextField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
|
||||
searchTextField.applyTheme()
|
||||
}
|
||||
|
||||
private func updateLeftView() {
|
||||
searchIcon.isHidden = true
|
||||
activityIndicator.isHidden = true
|
||||
backButton.isHidden = true
|
||||
|
||||
switch state {
|
||||
case .ready:
|
||||
searchIcon.isHidden = false
|
||||
case .searching:
|
||||
activityIndicator.isHidden = false
|
||||
activityIndicator.startAnimating()
|
||||
case .back:
|
||||
backButton.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
122
iphone/Maps/UI/Search/SearchOnMap/PlaceholderView.swift
Normal file
122
iphone/Maps/UI/Search/SearchOnMap/PlaceholderView.swift
Normal file
|
@ -0,0 +1,122 @@
|
|||
final class PlaceholderView: UIView {
|
||||
|
||||
private let activityIndicator: UIActivityIndicatorView?
|
||||
private let titleLabel = UILabel()
|
||||
private let subtitleLabel = UILabel()
|
||||
private let stackView = UIStackView()
|
||||
private var keyboardHeight: CGFloat = 0
|
||||
private var centerYConstraint: NSLayoutConstraint!
|
||||
private var containerModalYTranslation: CGFloat = 0
|
||||
private let minOffsetFromTheKeyboardTop: CGFloat = 20
|
||||
private let maxOffsetFromTheTop: CGFloat = 100
|
||||
|
||||
init(title: String? = nil, subtitle: String? = nil, hasActivityIndicator: Bool = false) {
|
||||
self.activityIndicator = hasActivityIndicator ? UIActivityIndicatorView() : nil
|
||||
super.init(frame: .zero)
|
||||
setupView(title: title, subtitle: subtitle)
|
||||
layoutView()
|
||||
setupKeyboardObservers()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
private func setupKeyboardObservers() {
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(keyboardWillShow(_:)),
|
||||
name: UIResponder.keyboardWillShowNotification,
|
||||
object: nil)
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(keyboardWillHide(_:)),
|
||||
name: UIResponder.keyboardWillHideNotification,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
@objc private func keyboardWillShow(_ notification: Notification) {
|
||||
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
|
||||
keyboardHeight = keyboardFrame.height
|
||||
reloadConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func keyboardWillHide(_ notification: Notification) {
|
||||
keyboardHeight = 0
|
||||
reloadConstraints()
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
if traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass {
|
||||
reloadConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
private func setupView(title: String?, subtitle: String?) {
|
||||
if let activityIndicator = activityIndicator {
|
||||
activityIndicator.hidesWhenStopped = true
|
||||
activityIndicator.startAnimating()
|
||||
if #available(iOS 13.0, *) {
|
||||
activityIndicator.style = .medium
|
||||
} else {
|
||||
activityIndicator.style = .gray
|
||||
}
|
||||
}
|
||||
|
||||
titleLabel.text = title
|
||||
titleLabel.setFontStyle(.medium16, color: .blackPrimary)
|
||||
titleLabel.textAlignment = .center
|
||||
|
||||
subtitleLabel.text = subtitle
|
||||
subtitleLabel.setFontStyle(.regular14, color: .blackSecondary)
|
||||
subtitleLabel.textAlignment = .center
|
||||
subtitleLabel.isHidden = subtitle == nil
|
||||
subtitleLabel.numberOfLines = 2
|
||||
|
||||
stackView.axis = .vertical
|
||||
stackView.alignment = .center
|
||||
stackView.spacing = 8
|
||||
}
|
||||
|
||||
private func layoutView() {
|
||||
if let activityIndicator = activityIndicator {
|
||||
stackView.addArrangedSubview(activityIndicator)
|
||||
}
|
||||
if let title = titleLabel.text, !title.isEmpty {
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
}
|
||||
if let subtitle = subtitleLabel.text, !subtitle.isEmpty {
|
||||
stackView.addArrangedSubview(subtitleLabel)
|
||||
}
|
||||
|
||||
addSubview(stackView)
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
centerYConstraint = stackView.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
stackView.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor, multiplier: 0.8),
|
||||
centerYConstraint
|
||||
])
|
||||
}
|
||||
|
||||
private func reloadConstraints() {
|
||||
let offset = keyboardHeight > 0 ? max(bounds.height / 2 - keyboardHeight, minOffsetFromTheKeyboardTop + stackView.frame.height) : containerModalYTranslation / 2
|
||||
let maxOffset = bounds.height / 2 - maxOffsetFromTheTop
|
||||
centerYConstraint.constant = -min(offset, maxOffset)
|
||||
layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ModallyPresentedViewController
|
||||
extension PlaceholderView: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
self.containerModalYTranslation = translationY
|
||||
reloadConstraints()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/// A transparent view that allows touch events to pass through to the MapViewController's view.
|
||||
///
|
||||
/// This view is used to enable interaction with the underlying map while still maintaining a
|
||||
/// transparent overlay. It does not block touch events but forwards them to the specified `passingView`.
|
||||
|
||||
final class MapPassthroughView: UIView {
|
||||
private weak var passingView: UIView?
|
||||
|
||||
init(passingView: UIView) {
|
||||
self.passingView = passingView
|
||||
super.init(frame: passingView.bounds)
|
||||
self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
self.alpha = 0
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
guard let passingView else { return nil }
|
||||
let pointInPassthroughView = passingView.convert(point, from: self)
|
||||
super.hitTest(point, with: event)
|
||||
if passingView.bounds.contains(pointInPassthroughView) {
|
||||
return MapViewController.shared()?.view.hitTest(point, with: event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
enum ModalScreenPresentationStep {
|
||||
case fullScreen
|
||||
case halfScreen
|
||||
case compact
|
||||
case hidden
|
||||
}
|
||||
|
||||
extension ModalScreenPresentationStep {
|
||||
private enum Constants {
|
||||
static let iPadWidth: CGFloat = 350
|
||||
static let compactHeightOffset: CGFloat = 120
|
||||
static let fullScreenHeightFactorPortrait: CGFloat = 0.1
|
||||
static let halfScreenHeightFactorPortrait: CGFloat = 0.55
|
||||
static let landscapeTopInset: CGFloat = 10
|
||||
}
|
||||
|
||||
var upper: ModalScreenPresentationStep {
|
||||
switch self {
|
||||
case .fullScreen:
|
||||
return .fullScreen
|
||||
case .halfScreen:
|
||||
return .fullScreen
|
||||
case .compact:
|
||||
return .halfScreen
|
||||
case .hidden:
|
||||
return .compact
|
||||
}
|
||||
}
|
||||
|
||||
var lower: ModalScreenPresentationStep {
|
||||
switch self {
|
||||
case .fullScreen:
|
||||
return .halfScreen
|
||||
case .halfScreen:
|
||||
return .compact
|
||||
case .compact:
|
||||
return .compact
|
||||
case .hidden:
|
||||
return .hidden
|
||||
}
|
||||
}
|
||||
|
||||
var first: ModalScreenPresentationStep {
|
||||
.fullScreen
|
||||
}
|
||||
|
||||
var last: ModalScreenPresentationStep {
|
||||
.compact
|
||||
}
|
||||
|
||||
func frame(for viewController: UIViewController, in containerView: UIView) -> CGRect {
|
||||
let isIPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let containerSize = containerView.bounds.size
|
||||
let safeAreaInsets = containerView.safeAreaInsets
|
||||
var frame = CGRect(origin: .zero, size: containerSize)
|
||||
|
||||
if isIPad {
|
||||
frame.size.width = Constants.iPadWidth
|
||||
switch self {
|
||||
case .hidden:
|
||||
frame.origin.x = -Constants.iPadWidth
|
||||
default:
|
||||
frame.origin.x = .zero
|
||||
}
|
||||
return frame
|
||||
}
|
||||
|
||||
let isPortraitOrientation = viewController.traitCollection.verticalSizeClass == .regular
|
||||
if isPortraitOrientation {
|
||||
switch self {
|
||||
case .fullScreen:
|
||||
frame.origin.y = containerSize.height * Constants.fullScreenHeightFactorPortrait
|
||||
case .halfScreen:
|
||||
frame.origin.y = containerSize.height * Constants.halfScreenHeightFactorPortrait
|
||||
case .compact:
|
||||
frame.origin.y = containerSize.height - Constants.compactHeightOffset
|
||||
case .hidden:
|
||||
frame.origin.y = containerSize.height
|
||||
}
|
||||
} else {
|
||||
frame.size.width = Constants.iPadWidth
|
||||
frame.origin.x = safeAreaInsets.left
|
||||
switch self {
|
||||
case .fullScreen:
|
||||
frame.origin.y = Constants.landscapeTopInset
|
||||
case .halfScreen, .compact:
|
||||
frame.origin.y = containerSize.height - Constants.compactHeightOffset
|
||||
case .hidden:
|
||||
frame.origin.y = containerSize.height
|
||||
}
|
||||
}
|
||||
return frame
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
protocol ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat)
|
||||
}
|
||||
|
||||
protocol SearchOnMapModalPresentationView: AnyObject {
|
||||
func setPresentationStep(_ step: ModalScreenPresentationStep)
|
||||
func close()
|
||||
}
|
||||
|
||||
final class SearchOnMapModalPresentationController: UIPresentationController {
|
||||
|
||||
private enum StepChangeAnimation {
|
||||
case slide
|
||||
case slideAndBounce
|
||||
}
|
||||
|
||||
private enum Constants {
|
||||
static let animationDuration: TimeInterval = kDefaultAnimationDuration
|
||||
static let springDamping: CGFloat = 0.85
|
||||
static let springVelocity: CGFloat = 0.2
|
||||
static let iPhoneCornerRadius: CGFloat = 10
|
||||
static let slowSwipeVelocity: CGFloat = 500
|
||||
static let fastSwipeDownVelocity: CGFloat = 4000
|
||||
static let fastSwipeUpVelocity: CGFloat = 3000
|
||||
static let translationThreshold: CGFloat = 50
|
||||
static let panGestureThreshold: CGFloat = 5
|
||||
}
|
||||
|
||||
private var initialTranslationY: CGFloat = 0
|
||||
private weak var interactor: SearchOnMapInteractor? {
|
||||
(presentedViewController as? SearchOnMapViewController)?.interactor
|
||||
}
|
||||
// TODO: replace with set of steps passed from the outside
|
||||
private var presentationStep: ModalScreenPresentationStep = .fullScreen
|
||||
private var internalScrollViewContentOffset: CGFloat = 0
|
||||
private var maxAvailableFrameOfPresentedView: CGRect = .zero
|
||||
|
||||
// MARK: - Init
|
||||
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
|
||||
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
|
||||
|
||||
iPhoneSpecific {
|
||||
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
|
||||
panGestureRecognizer.delegate = self
|
||||
presentedViewController.view.addGestureRecognizer(panGestureRecognizer)
|
||||
if let presentedViewController = presentedViewController as? SearchOnMapView {
|
||||
presentedViewController.scrollViewDelegate = self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle
|
||||
override func containerViewWillLayoutSubviews() {
|
||||
super.containerViewWillLayoutSubviews()
|
||||
presentedView?.frame = frameOfPresentedViewInContainerView
|
||||
}
|
||||
|
||||
override func presentationTransitionWillBegin() {
|
||||
guard let containerView else { return }
|
||||
containerView.backgroundColor = .clear
|
||||
let passThroughView = MapPassthroughView(passingView: containerView)
|
||||
containerView.addSubview(passThroughView)
|
||||
}
|
||||
|
||||
override func presentationTransitionDidEnd(_ completed: Bool) {
|
||||
translationYDidUpdate(presentedView?.frame.origin.y ?? 0)
|
||||
}
|
||||
|
||||
override func dismissalTransitionDidEnd(_ completed: Bool) {
|
||||
super.dismissalTransitionDidEnd(completed)
|
||||
if completed {
|
||||
presentedView?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
updateMaxAvailableFrameOfPresentedView()
|
||||
}
|
||||
|
||||
// MARK: - Layout
|
||||
override var frameOfPresentedViewInContainerView: CGRect {
|
||||
guard let containerView else { return .zero }
|
||||
let frame = presentationStep.frame(for: presentedViewController, in: containerView)
|
||||
updateMaxAvailableFrameOfPresentedView()
|
||||
return frame
|
||||
}
|
||||
|
||||
private func updateMaxAvailableFrameOfPresentedView() {
|
||||
guard let containerView else { return }
|
||||
maxAvailableFrameOfPresentedView = ModalScreenPresentationStep.fullScreen.frame(for: presentedViewController, in: containerView)
|
||||
}
|
||||
|
||||
private func updateSideButtonsAvailableArea(_ newY: CGFloat) {
|
||||
iPhoneSpecific {
|
||||
guard presentedViewController.traitCollection.verticalSizeClass != .compact else { return }
|
||||
var sideButtonsAvailableArea = MWMSideButtons.getAvailableArea()
|
||||
sideButtonsAvailableArea.size.height = newY - sideButtonsAvailableArea.origin.y
|
||||
MWMSideButtons.updateAvailableArea(sideButtonsAvailableArea)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Pan gesture handling
|
||||
@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
|
||||
guard let presentedView, maxAvailableFrameOfPresentedView != .zero else { return }
|
||||
interactor?.handle(.didStartDraggingSearch)
|
||||
|
||||
let translation = gesture.translation(in: presentedView)
|
||||
let velocity = gesture.velocity(in: presentedView)
|
||||
|
||||
switch gesture.state {
|
||||
case .began:
|
||||
initialTranslationY = presentedView.frame.origin.y
|
||||
case .changed:
|
||||
let newY = max(max(initialTranslationY + translation.y, 0), maxAvailableFrameOfPresentedView.origin.y)
|
||||
presentedView.frame.origin.y = newY
|
||||
updateSideButtonsAvailableArea(newY)
|
||||
translationYDidUpdate(newY)
|
||||
case .ended:
|
||||
let nextStep: ModalScreenPresentationStep
|
||||
if velocity.y > Constants.fastSwipeDownVelocity {
|
||||
interactor?.handle(.closeSearch)
|
||||
return
|
||||
} else if velocity.y < -Constants.fastSwipeUpVelocity {
|
||||
nextStep = .fullScreen // fast swipe up
|
||||
} else if velocity.y > Constants.slowSwipeVelocity || translation.y > Constants.translationThreshold {
|
||||
if presentationStep == .compact {
|
||||
interactor?.handle(.closeSearch)
|
||||
return
|
||||
}
|
||||
nextStep = presentationStep.lower // regular swipe down
|
||||
} else if velocity.y < -Constants.slowSwipeVelocity || translation.y < -Constants.translationThreshold {
|
||||
nextStep = presentationStep.upper // regular swipe up
|
||||
} else {
|
||||
// TODO: swipe to closest step on the big translation
|
||||
nextStep = presentationStep
|
||||
}
|
||||
let animation: StepChangeAnimation = abs(velocity.y) > Constants.slowSwipeVelocity ? .slideAndBounce : .slide
|
||||
animateTo(nextStep, animation: animation)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func animateTo(_ presentationStep: ModalScreenPresentationStep, animation: StepChangeAnimation = .slide) {
|
||||
guard let presentedView, let containerView else { return }
|
||||
self.presentationStep = presentationStep
|
||||
interactor?.handle(.didUpdatePresentationStep(presentationStep))
|
||||
|
||||
let updatedFrame = presentationStep.frame(for: presentedViewController, in: containerView)
|
||||
let targetYTranslation = updatedFrame.origin.y
|
||||
|
||||
switch animation {
|
||||
case .slide:
|
||||
UIView.animate(withDuration: Constants.animationDuration,
|
||||
delay: 0,
|
||||
options: .curveEaseOut,
|
||||
animations: { [weak self] in
|
||||
presentedView.frame = updatedFrame
|
||||
self?.translationYDidUpdate(targetYTranslation)
|
||||
self?.updateSideButtonsAvailableArea(targetYTranslation)
|
||||
})
|
||||
case .slideAndBounce:
|
||||
UIView.animate(withDuration: Constants.animationDuration,
|
||||
delay: 0,
|
||||
usingSpringWithDamping: Constants.springDamping,
|
||||
initialSpringVelocity: Constants.springVelocity,
|
||||
options: .curveLinear,
|
||||
animations: { [weak self] in
|
||||
presentedView.frame = updatedFrame
|
||||
self?.translationYDidUpdate(targetYTranslation)
|
||||
self?.updateSideButtonsAvailableArea(targetYTranslation)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SearchOnMapModalPresentationView
|
||||
extension SearchOnMapModalPresentationController: SearchOnMapModalPresentationView {
|
||||
func setPresentationStep(_ step: ModalScreenPresentationStep) {
|
||||
guard presentationStep != step else { return }
|
||||
animateTo(step)
|
||||
}
|
||||
|
||||
func close() {
|
||||
guard let containerView else { return }
|
||||
updateSideButtonsAvailableArea(containerView.frame.height)
|
||||
presentedViewController.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ModallyPresentedViewController
|
||||
extension SearchOnMapModalPresentationController: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
iPhoneSpecific {
|
||||
(presentedViewController as? SearchOnMapViewController)?.translationYDidUpdate(translationY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIGestureRecognizerDelegate
|
||||
extension SearchOnMapModalPresentationController: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
// threshold is used to soften transition from the internal scroll zero content offset
|
||||
internalScrollViewContentOffset < Constants.panGestureThreshold
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SearchOnMapScrollViewDelegate
|
||||
extension SearchOnMapModalPresentationController: SearchOnMapScrollViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
guard let presentedView else { return }
|
||||
let hasReachedTheTop = Int(presentedView.frame.origin.y) > Int(maxAvailableFrameOfPresentedView.origin.y)
|
||||
let hasZeroContentOffset = internalScrollViewContentOffset == 0
|
||||
if hasReachedTheTop && hasZeroContentOffset {
|
||||
// prevent the internal scroll view scrolling
|
||||
scrollView.contentOffset.y = internalScrollViewContentOffset
|
||||
return
|
||||
}
|
||||
internalScrollViewContentOffset = scrollView.contentOffset.y
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
@objc
|
||||
final class SearchOnMapModalTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
|
||||
|
||||
weak var presentationController: SearchOnMapModalPresentationView?
|
||||
|
||||
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? {
|
||||
isIPad ? SideMenuPresentationAnimator() : nil
|
||||
}
|
||||
|
||||
func animationController(forDismissed dismissed: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? {
|
||||
isIPad ? SideMenuDismissalAnimator() : nil
|
||||
}
|
||||
|
||||
func presentationController(forPresented presented: UIViewController,
|
||||
presenting: UIViewController?,
|
||||
source: UIViewController) -> UIPresentationController? {
|
||||
let presentationController = SearchOnMapModalPresentationController(presentedViewController: presented, presenting: presenting)
|
||||
self.presentationController = presentationController
|
||||
return presentationController
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
final class SideMenuDismissalAnimator: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return kDefaultAnimationDuration / 2
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard let fromVC = transitionContext.viewController(forKey: .from) else { return }
|
||||
let initialFrame = transitionContext.initialFrame(for: fromVC)
|
||||
let targetFrame = initialFrame.offsetBy(dx: -initialFrame.width, dy: 0)
|
||||
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext),
|
||||
delay: .zero,
|
||||
options: .curveEaseIn,
|
||||
animations: {
|
||||
fromVC.view.frame = targetFrame
|
||||
},
|
||||
completion: {
|
||||
fromVC.view.removeFromSuperview()
|
||||
transitionContext.completeTransition($0)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
final class SideMenuPresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return kDefaultAnimationDuration / 2
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard let toVC = transitionContext.viewController(forKey: .to) else { return }
|
||||
let containerView = transitionContext.containerView
|
||||
let finalFrame = transitionContext.finalFrame(for: toVC)
|
||||
let originFrame = finalFrame.offsetBy(dx: -finalFrame.width, dy: 0)
|
||||
containerView.addSubview(toVC.view)
|
||||
toVC.view.frame = originFrame
|
||||
toVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext),
|
||||
delay: .zero,
|
||||
options: .curveEaseOut,
|
||||
animations: {
|
||||
toVC.view.frame = finalFrame
|
||||
},
|
||||
completion: {
|
||||
transitionContext.completeTransition($0)
|
||||
})
|
||||
}
|
||||
}
|
113
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift
Normal file
113
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift
Normal file
|
@ -0,0 +1,113 @@
|
|||
protocol SearchOnMapHeaderViewDelegate: UISearchBarDelegate {
|
||||
func cancelButtonDidTap()
|
||||
}
|
||||
|
||||
final class SearchOnMapHeaderView: UIView {
|
||||
weak var delegate: SearchOnMapHeaderViewDelegate? {
|
||||
didSet {
|
||||
searchBar.delegate = delegate
|
||||
}
|
||||
}
|
||||
|
||||
private enum Constants {
|
||||
static let grabberHeight: CGFloat = 5
|
||||
static let grabberWidth: CGFloat = 36
|
||||
static let grabberTopMargin: CGFloat = 5
|
||||
static let cancelButtonInsets: UIEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 8)
|
||||
}
|
||||
|
||||
private let grabberView = UIView()
|
||||
private let searchBar = UISearchBar()
|
||||
private let cancelButton = UIButton()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupView()
|
||||
layoutView()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func setupView() {
|
||||
setStyle(.searchHeader)
|
||||
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
|
||||
setupGrabberView()
|
||||
setupSearchBar()
|
||||
setupCancelButton()
|
||||
}
|
||||
|
||||
private func setupGrabberView() {
|
||||
grabberView.setStyle(.background)
|
||||
grabberView.layer.setCorner(radius: Constants.grabberHeight / 2)
|
||||
iPadSpecific { [weak self] in
|
||||
self?.grabberView.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
private func setupSearchBar() {
|
||||
searchBar.placeholder = L("search")
|
||||
searchBar.showsCancelButton = false
|
||||
if #available(iOS 13.0, *) {
|
||||
searchBar.searchTextField.clearButtonMode = .always
|
||||
searchBar.returnKeyType = .search
|
||||
searchBar.searchTextField.enablesReturnKeyAutomatically = true
|
||||
}
|
||||
}
|
||||
|
||||
private func setupCancelButton() {
|
||||
cancelButton.tintColor = .whitePrimaryText()
|
||||
cancelButton.setStyle(.clearBackground)
|
||||
cancelButton.setTitle(L("cancel"), for: .normal)
|
||||
cancelButton.addTarget(self, action: #selector(cancelButtonTapped), for: .touchUpInside)
|
||||
}
|
||||
|
||||
private func layoutView() {
|
||||
addSubview(grabberView)
|
||||
addSubview(searchBar)
|
||||
addSubview(cancelButton)
|
||||
|
||||
grabberView.translatesAutoresizingMaskIntoConstraints = false
|
||||
searchBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
cancelButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
grabberView.topAnchor.constraint(equalTo: topAnchor, constant: Constants.grabberTopMargin),
|
||||
grabberView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
grabberView.widthAnchor.constraint(equalToConstant: Constants.grabberWidth),
|
||||
grabberView.heightAnchor.constraint(equalToConstant: Constants.grabberHeight),
|
||||
|
||||
searchBar.topAnchor.constraint(equalTo: grabberView.bottomAnchor),
|
||||
searchBar.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
searchBar.trailingAnchor.constraint(equalTo: cancelButton.leadingAnchor, constant: -Constants.cancelButtonInsets.left),
|
||||
|
||||
cancelButton.centerYAnchor.constraint(equalTo: searchBar.centerYAnchor),
|
||||
cancelButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.cancelButtonInsets.right),
|
||||
|
||||
bottomAnchor.constraint(equalTo: searchBar.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
@objc private func cancelButtonTapped() {
|
||||
delegate?.cancelButtonDidTap()
|
||||
}
|
||||
|
||||
func setSearchText(_ text: String) {
|
||||
searchBar.text = text
|
||||
}
|
||||
|
||||
func setIsSearching(_ isSearching: Bool) {
|
||||
if isSearching {
|
||||
searchBar.becomeFirstResponder()
|
||||
} else if searchBar.isFirstResponder {
|
||||
searchBar.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
var searchText: SearchOnMap.SearchText {
|
||||
SearchOnMap.SearchText(searchBar.text ?? "", locale: searchBar.textInputMode?.primaryLanguage)
|
||||
}
|
||||
}
|
165
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift
Normal file
165
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift
Normal file
|
@ -0,0 +1,165 @@
|
|||
final class SearchOnMapInteractor: NSObject {
|
||||
|
||||
private let presenter: SearchOnMapPresenter
|
||||
private let searchManager: SearchManager.Type
|
||||
private let routeManager: MWMRouter.Type
|
||||
private var isUpdatesDisabled = false
|
||||
private var showResultsOnMap: Bool = false
|
||||
|
||||
var routingTooltipSearch: SearchOnMapRoutingTooltipSearch = .none
|
||||
|
||||
init(presenter: SearchOnMapPresenter,
|
||||
searchManager: SearchManager.Type = Search.self,
|
||||
routeManager: MWMRouter.Type = MWMRouter.self) {
|
||||
self.presenter = presenter
|
||||
self.searchManager = searchManager
|
||||
self.routeManager = routeManager
|
||||
super.init()
|
||||
searchManager.add(self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
searchManager.remove(self)
|
||||
}
|
||||
|
||||
func handle(_ event: SearchOnMap.Request) {
|
||||
let response = resolve(event)
|
||||
presenter.process(response)
|
||||
}
|
||||
|
||||
private func resolve(_ event: SearchOnMap.Request) -> SearchOnMap.Response {
|
||||
switch event {
|
||||
case .openSearch:
|
||||
return .showHistoryAndCategory
|
||||
case .hideSearch:
|
||||
return .setSearchScreenHidden(true)
|
||||
case .didStartDraggingSearch:
|
||||
return .setIsTyping(false)
|
||||
case .didStartTyping:
|
||||
return .setIsTyping(true)
|
||||
case .didType(let searchText):
|
||||
return processTypedText(searchText)
|
||||
case .clearButtonDidTap:
|
||||
return processClearButtonDidTap()
|
||||
case .didSelectText(let searchText, let isCategory):
|
||||
return processSelectedText(searchText, isCategory: isCategory)
|
||||
case .searchButtonDidTap(let searchText):
|
||||
return processSearchButtonDidTap(searchText)
|
||||
case .didSelectResult(let result, let index, let searchText):
|
||||
return processSelectedResult(result, index: index, searchText: searchText)
|
||||
case .didSelectPlaceOnMap:
|
||||
return isIPad ? .none : .setSearchScreenHidden(true)
|
||||
case .didDeselectPlaceOnMap:
|
||||
return deselectPlaceOnMap()
|
||||
case .didStartDraggingMap:
|
||||
return .setSearchScreenCompact
|
||||
case .didUpdatePresentationStep(let step):
|
||||
return .updatePresentationStep(step)
|
||||
case .closeSearch:
|
||||
return closeSearch()
|
||||
}
|
||||
}
|
||||
|
||||
private func processClearButtonDidTap() -> SearchOnMap.Response {
|
||||
isUpdatesDisabled = true
|
||||
searchManager.clear()
|
||||
return .clearSearch
|
||||
}
|
||||
|
||||
private func processSearchButtonDidTap(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response {
|
||||
searchManager.saveQuery(searchText.text,
|
||||
forInputLocale: searchText.locale)
|
||||
showResultsOnMap = true
|
||||
return .showOnTheMap
|
||||
}
|
||||
|
||||
private func processTypedText(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response {
|
||||
isUpdatesDisabled = false
|
||||
showResultsOnMap = true
|
||||
searchManager.searchQuery(searchText.text,
|
||||
forInputLocale: searchText.locale,
|
||||
withCategory: false)
|
||||
return .startSearching
|
||||
}
|
||||
|
||||
private func processSelectedText(_ searchText: SearchOnMap.SearchText, isCategory: Bool) -> SearchOnMap.Response {
|
||||
isUpdatesDisabled = false
|
||||
searchManager.saveQuery(searchText.text,
|
||||
forInputLocale: searchText.locale)
|
||||
searchManager.searchQuery(searchText.text,
|
||||
forInputLocale: searchText.locale,
|
||||
withCategory: isCategory)
|
||||
showResultsOnMap = true
|
||||
return .selectText(searchText.text)
|
||||
}
|
||||
|
||||
private func processSelectedResult(_ result: SearchResult, index: Int, searchText: SearchOnMap.SearchText) -> SearchOnMap.Response {
|
||||
switch result.itemType {
|
||||
case .regular:
|
||||
searchManager.saveQuery(searchText.text,
|
||||
forInputLocale:searchText.locale)
|
||||
switch routingTooltipSearch {
|
||||
case .none:
|
||||
searchManager.showResult(at: UInt(index))
|
||||
case .start:
|
||||
let point = MWMRoutePoint(cgPoint: result.point,
|
||||
title: result.titleText,
|
||||
subtitle: result.addressText,
|
||||
type: .start,
|
||||
intermediateIndex: 0)
|
||||
routeManager.build(from: point, bestRouter: false)
|
||||
case .finish:
|
||||
let point = MWMRoutePoint(cgPoint: result.point,
|
||||
title: result.titleText,
|
||||
subtitle: result.addressText,
|
||||
type: .finish,
|
||||
intermediateIndex: 0)
|
||||
routeManager.build(to: point, bestRouter: false)
|
||||
@unknown default:
|
||||
fatalError("Unsupported routingTooltipSearch")
|
||||
}
|
||||
return isIPad ? .none : .setSearchScreenHidden(true)
|
||||
case .suggestion:
|
||||
searchManager.searchQuery(result.suggestion,
|
||||
forInputLocale: searchText.locale,
|
||||
withCategory: result.isPureSuggest)
|
||||
return .selectText(result.suggestion)
|
||||
@unknown default:
|
||||
fatalError("Unsupported result type")
|
||||
}
|
||||
}
|
||||
|
||||
private func deselectPlaceOnMap() -> SearchOnMap.Response {
|
||||
routingTooltipSearch = .none
|
||||
searchManager.showViewportSearchResultsOnMap()
|
||||
return .setSearchScreenHidden(false)
|
||||
}
|
||||
|
||||
private func closeSearch() -> SearchOnMap.Response {
|
||||
routingTooltipSearch = .none
|
||||
isUpdatesDisabled = true
|
||||
showResultsOnMap = false
|
||||
searchManager.clear()
|
||||
return .close
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MWMSearchObserver
|
||||
extension SearchOnMapInteractor: MWMSearchObserver {
|
||||
func onSearchCompleted() {
|
||||
guard !isUpdatesDisabled else { return }
|
||||
let results = searchManager.getResults()
|
||||
if showResultsOnMap && !results.isEmpty {
|
||||
searchManager.showEverywhereSearchResultsOnMap()
|
||||
showResultsOnMap = false
|
||||
}
|
||||
presenter.process(.showResults(SearchOnMap.SearchResults(results), isSearchCompleted: true))
|
||||
}
|
||||
|
||||
func onSearchResultsUpdated() {
|
||||
guard !isUpdatesDisabled else { return }
|
||||
let results = searchManager.getResults()
|
||||
guard !results.isEmpty else { return }
|
||||
presenter.process(.showResults(SearchOnMap.SearchResults(results), isSearchCompleted: false))
|
||||
}
|
||||
}
|
96
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift
Normal file
96
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift
Normal file
|
@ -0,0 +1,96 @@
|
|||
@objc
|
||||
enum SearchOnMapState: Int {
|
||||
case searching
|
||||
case hidden
|
||||
case closed
|
||||
}
|
||||
|
||||
@objc
|
||||
enum SearchOnMapRoutingTooltipSearch: Int {
|
||||
case none
|
||||
case start
|
||||
case finish
|
||||
}
|
||||
|
||||
@objc
|
||||
protocol SearchOnMapManagerObserver: AnyObject {
|
||||
func searchManager(didChangeState state: SearchOnMapState)
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
final class SearchOnMapManager: NSObject {
|
||||
private let navigationController: UINavigationController
|
||||
private weak var interactor: SearchOnMapInteractor?
|
||||
private let observers = ListenerContainer<SearchOnMapManagerObserver>()
|
||||
|
||||
// MARK: - Public properties
|
||||
weak var viewController: UIViewController?
|
||||
var isSearching: Bool { viewController != nil }
|
||||
|
||||
init(navigationController: UINavigationController = MapViewController.shared()!.navigationController!) {
|
||||
self.navigationController = navigationController
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
func startSearching(isRouting: Bool) {
|
||||
if viewController != nil {
|
||||
interactor?.handle(.openSearch)
|
||||
return
|
||||
}
|
||||
FrameworkHelper.deactivateMapSelection()
|
||||
let viewController = buildViewController(isRouting: isRouting)
|
||||
self.viewController = viewController
|
||||
self.interactor = viewController.interactor
|
||||
navigationController.present(viewController, animated: true)
|
||||
}
|
||||
|
||||
func hide() {
|
||||
interactor?.handle(.hideSearch)
|
||||
}
|
||||
|
||||
func close() {
|
||||
interactor?.handle(.closeSearch)
|
||||
}
|
||||
|
||||
func setRoutingTooltip(_ tooltip: SearchOnMapRoutingTooltipSearch) {
|
||||
interactor?.routingTooltipSearch = tooltip
|
||||
}
|
||||
|
||||
func setPlaceOnMapSelected(_ isSelected: Bool) {
|
||||
interactor?.handle(isSelected ? .didSelectPlaceOnMap : .didDeselectPlaceOnMap)
|
||||
}
|
||||
|
||||
func setMapIsDragging() {
|
||||
interactor?.handle(.didStartDraggingMap)
|
||||
}
|
||||
|
||||
func searchText(_ text: String, locale: String, isCategory: Bool) {
|
||||
let searchText = SearchOnMap.SearchText(text, locale: locale)
|
||||
interactor?.handle(.didSelectText(searchText, isCategory: isCategory))
|
||||
}
|
||||
|
||||
func addObserver(_ observer: SearchOnMapManagerObserver) {
|
||||
observers.addListener(observer)
|
||||
}
|
||||
|
||||
func removeObserver(_ observer: SearchOnMapManagerObserver) {
|
||||
observers.removeListener(observer)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func buildViewController(isRouting: Bool) -> SearchOnMapViewController {
|
||||
let transitioningManager = SearchOnMapModalTransitionManager()
|
||||
let presenter = SearchOnMapPresenter(transitionManager: transitioningManager,
|
||||
isRouting: isRouting,
|
||||
didChangeState: { [weak self] state in
|
||||
guard let self else { return }
|
||||
self.observers.forEach { observer in observer.searchManager(didChangeState: state) }
|
||||
})
|
||||
let interactor = SearchOnMapInteractor(presenter: presenter)
|
||||
let viewController = SearchOnMapViewController(interactor: interactor)
|
||||
presenter.view = viewController
|
||||
viewController.modalPresentationStyle = .custom
|
||||
viewController.transitioningDelegate = transitioningManager
|
||||
return viewController
|
||||
}
|
||||
}
|
94
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift
Normal file
94
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift
Normal file
|
@ -0,0 +1,94 @@
|
|||
enum SearchOnMap {
|
||||
struct ViewModel: Equatable {
|
||||
enum ContentState: Equatable {
|
||||
case historyAndCategory
|
||||
case results(SearchResults)
|
||||
case noResults
|
||||
case searching
|
||||
}
|
||||
|
||||
var isTyping: Bool
|
||||
var skipSuggestions: Bool
|
||||
var searchingText: String?
|
||||
var contentState: ContentState
|
||||
var presentationStep: ModalScreenPresentationStep
|
||||
}
|
||||
|
||||
struct SearchResults: Equatable {
|
||||
let results: [SearchResult]
|
||||
let hasPartialMatch: Bool
|
||||
let isEmpty: Bool
|
||||
let count: Int
|
||||
let suggestionsCount: Int
|
||||
|
||||
init(_ results: [SearchResult]) {
|
||||
self.results = results
|
||||
self.hasPartialMatch = !results.allSatisfy { $0.highlightRanges.isEmpty }
|
||||
self.isEmpty = results.isEmpty
|
||||
self.count = results.count
|
||||
self.suggestionsCount = results.filter { $0.itemType == .suggestion }.count
|
||||
}
|
||||
}
|
||||
|
||||
struct SearchText {
|
||||
let text: String
|
||||
let locale: String
|
||||
|
||||
init(_ text: String, locale: String? = nil) {
|
||||
self.text = text
|
||||
self.locale = locale ?? AppInfo.shared().languageId
|
||||
}
|
||||
}
|
||||
|
||||
enum Request {
|
||||
case openSearch
|
||||
case hideSearch
|
||||
case closeSearch
|
||||
case didStartDraggingSearch
|
||||
case didStartDraggingMap
|
||||
case didStartTyping
|
||||
case didType(SearchText)
|
||||
case didSelectText(SearchText, isCategory: Bool)
|
||||
case didSelectResult(SearchResult, atIndex: Int, withSearchText: SearchText)
|
||||
case searchButtonDidTap(SearchText)
|
||||
case clearButtonDidTap
|
||||
case didSelectPlaceOnMap
|
||||
case didDeselectPlaceOnMap
|
||||
case didUpdatePresentationStep(ModalScreenPresentationStep)
|
||||
}
|
||||
|
||||
enum Response: Equatable {
|
||||
case startSearching
|
||||
case showOnTheMap
|
||||
case setIsTyping(Bool)
|
||||
case showHistoryAndCategory
|
||||
case showResults(SearchResults, isSearchCompleted: Bool = false)
|
||||
case selectText(String?)
|
||||
case clearSearch
|
||||
case setSearchScreenHidden(Bool)
|
||||
case setSearchScreenCompact
|
||||
case updatePresentationStep(ModalScreenPresentationStep)
|
||||
case close
|
||||
case none
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchOnMap.SearchResults {
|
||||
static let empty = SearchOnMap.SearchResults([])
|
||||
|
||||
subscript(index: Int) -> SearchResult {
|
||||
results[index]
|
||||
}
|
||||
|
||||
mutating func skipSuggestions() {
|
||||
self = SearchOnMap.SearchResults(results.filter { $0.itemType != .suggestion })
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchOnMap.ViewModel {
|
||||
static let initial = SearchOnMap.ViewModel(isTyping: false,
|
||||
skipSuggestions: false,
|
||||
searchingText: nil,
|
||||
contentState: .historyAndCategory,
|
||||
presentationStep: .fullScreen)
|
||||
}
|
117
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift
Normal file
117
iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift
Normal file
|
@ -0,0 +1,117 @@
|
|||
final class SearchOnMapPresenter {
|
||||
typealias Response = SearchOnMap.Response
|
||||
typealias ViewModel = SearchOnMap.ViewModel
|
||||
|
||||
weak var view: SearchOnMapView?
|
||||
weak var presentationView: SearchOnMapModalPresentationView? { transitionManager.presentationController }
|
||||
|
||||
private var searchState: SearchOnMapState = .searching {
|
||||
didSet {
|
||||
guard searchState != oldValue else { return }
|
||||
didChangeState?(searchState)
|
||||
}
|
||||
}
|
||||
|
||||
private let transitionManager: SearchOnMapModalTransitionManager
|
||||
private var viewModel: ViewModel = .initial
|
||||
private var isRouting: Bool
|
||||
private var didChangeState: ((SearchOnMapState) -> Void)?
|
||||
|
||||
init(transitionManager: SearchOnMapModalTransitionManager, isRouting: Bool, didChangeState: ((SearchOnMapState) -> Void)?) {
|
||||
self.transitionManager = transitionManager
|
||||
self.isRouting = isRouting
|
||||
self.didChangeState = didChangeState
|
||||
didChangeState?(searchState)
|
||||
}
|
||||
|
||||
func process(_ response: SearchOnMap.Response) {
|
||||
guard response != .none else { return }
|
||||
|
||||
if response == .close {
|
||||
searchState = .closed
|
||||
presentationView?.close()
|
||||
return
|
||||
}
|
||||
|
||||
let showSearch = response == .setSearchScreenHidden(false) || response == .showHistoryAndCategory
|
||||
guard viewModel.presentationStep != .hidden || showSearch else {
|
||||
return
|
||||
}
|
||||
|
||||
let newViewModel = resolve(action: response, with: viewModel)
|
||||
if viewModel != newViewModel {
|
||||
viewModel = newViewModel
|
||||
view?.render(newViewModel)
|
||||
searchState = newViewModel.presentationStep.searchState
|
||||
presentationView?.setPresentationStep(newViewModel.presentationStep)
|
||||
}
|
||||
}
|
||||
|
||||
private func resolve(action: Response, with previousViewModel: ViewModel) -> ViewModel {
|
||||
var viewModel = previousViewModel
|
||||
viewModel.searchingText = nil // should not be nil only when the text is passed to the search field
|
||||
|
||||
switch action {
|
||||
case .startSearching:
|
||||
viewModel.isTyping = true
|
||||
viewModel.skipSuggestions = false
|
||||
viewModel.contentState = .searching
|
||||
case .showOnTheMap:
|
||||
viewModel.isTyping = false
|
||||
viewModel.skipSuggestions = true
|
||||
viewModel.presentationStep = isRouting ? .hidden : .halfScreen
|
||||
if case .results(var results) = viewModel.contentState, !results.isEmpty {
|
||||
results.skipSuggestions()
|
||||
viewModel.contentState = .results(results)
|
||||
}
|
||||
case .setIsTyping(let isSearching):
|
||||
viewModel.isTyping = isSearching
|
||||
if isSearching {
|
||||
viewModel.presentationStep = .fullScreen
|
||||
}
|
||||
case .showHistoryAndCategory:
|
||||
viewModel.isTyping = true
|
||||
viewModel.contentState = .historyAndCategory
|
||||
viewModel.presentationStep = .fullScreen
|
||||
case .showResults(var searchResults, let isSearchCompleted):
|
||||
if (viewModel.skipSuggestions) {
|
||||
searchResults.skipSuggestions()
|
||||
}
|
||||
viewModel.contentState = searchResults.isEmpty && isSearchCompleted ? .noResults : .results(searchResults)
|
||||
case .selectText(let text):
|
||||
viewModel.isTyping = false
|
||||
viewModel.skipSuggestions = false
|
||||
viewModel.searchingText = text
|
||||
viewModel.contentState = .searching
|
||||
viewModel.presentationStep = isRouting ? .hidden : .halfScreen
|
||||
case .clearSearch:
|
||||
viewModel.searchingText = ""
|
||||
viewModel.isTyping = true
|
||||
viewModel.skipSuggestions = false
|
||||
viewModel.contentState = .historyAndCategory
|
||||
viewModel.presentationStep = .fullScreen
|
||||
case .setSearchScreenHidden(let isHidden):
|
||||
viewModel.isTyping = false
|
||||
viewModel.presentationStep = isHidden ? .hidden : (isRouting ? .fullScreen : .halfScreen)
|
||||
case .setSearchScreenCompact:
|
||||
viewModel.isTyping = false
|
||||
viewModel.presentationStep = .compact
|
||||
case .updatePresentationStep(let step):
|
||||
viewModel.presentationStep = step
|
||||
case .close, .none:
|
||||
break
|
||||
}
|
||||
return viewModel
|
||||
}
|
||||
}
|
||||
|
||||
private extension ModalScreenPresentationStep {
|
||||
var searchState: SearchOnMapState {
|
||||
switch self {
|
||||
case .fullScreen, .halfScreen, .compact:
|
||||
return .searching
|
||||
case .hidden:
|
||||
return .hidden
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
protocol SearchOnMapView: AnyObject {
|
||||
var scrollViewDelegate: SearchOnMapScrollViewDelegate? { get set }
|
||||
|
||||
func render(_ viewModel: SearchOnMap.ViewModel)
|
||||
}
|
||||
|
||||
@objc
|
||||
protocol SearchOnMapScrollViewDelegate: AnyObject {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView)
|
||||
}
|
||||
|
||||
final class SearchOnMapViewController: UIViewController {
|
||||
typealias ViewModel = SearchOnMap.ViewModel
|
||||
typealias ContentState = SearchOnMap.ViewModel.ContentState
|
||||
typealias SearchText = SearchOnMap.SearchText
|
||||
|
||||
fileprivate enum Constants {
|
||||
static let categoriesHeight: CGFloat = 100
|
||||
static let filtersHeight: CGFloat = 50
|
||||
static let keyboardAnimationDuration: CGFloat = 0.3
|
||||
static let cancelButtonInsets: UIEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 8)
|
||||
static let estimatedRowHeight: CGFloat = 80
|
||||
}
|
||||
|
||||
let interactor: SearchOnMapInteractor
|
||||
weak var scrollViewDelegate: SearchOnMapScrollViewDelegate?
|
||||
|
||||
private var searchResults = SearchOnMap.SearchResults([])
|
||||
|
||||
// MARK: - UI Elements
|
||||
private let headerView = SearchOnMapHeaderView()
|
||||
private let containerView = UIView()
|
||||
private let resultsTableView = UITableView()
|
||||
private let historyAndCategoryTabViewController = SearchTabViewController()
|
||||
// TODO: implement filters
|
||||
private let filtersCollectionView: UICollectionView = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.scrollDirection = .horizontal
|
||||
return UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
}()
|
||||
private var searchingActivityView = PlaceholderView(hasActivityIndicator: true)
|
||||
private var containerModalYTranslation: CGFloat = 0
|
||||
private var searchNoResultsView = PlaceholderView(title: L("search_not_found"),
|
||||
subtitle: L("search_not_found_query"))
|
||||
|
||||
// MARK: - Init
|
||||
init(interactor: SearchOnMapInteractor) {
|
||||
self.interactor = interactor
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setupViews()
|
||||
layoutViews()
|
||||
interactor.handle(.openSearch)
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
headerView.setIsSearching(false)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupViews() {
|
||||
view.setStyle(.background)
|
||||
setupTapGestureRecognizer()
|
||||
setupHeaderView()
|
||||
setupContainerView()
|
||||
setupResultsTableView()
|
||||
setupHistoryAndCategoryTabView()
|
||||
setupResultsTableView()
|
||||
setupFiltersCollectionView()
|
||||
}
|
||||
|
||||
private func setupTapGestureRecognizer() {
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapOutside))
|
||||
tapGesture.cancelsTouchesInView = false
|
||||
view.addGestureRecognizer(tapGesture)
|
||||
}
|
||||
|
||||
private func setupHeaderView() {
|
||||
headerView.delegate = self
|
||||
}
|
||||
|
||||
private func setupContainerView() {
|
||||
containerView.setStyle(.background)
|
||||
}
|
||||
|
||||
private func setupResultsTableView() {
|
||||
resultsTableView.setStyle(.background)
|
||||
resultsTableView.estimatedRowHeight = Constants.estimatedRowHeight
|
||||
resultsTableView.rowHeight = UITableView.automaticDimension
|
||||
resultsTableView.registerNib(cellClass: SearchSuggestionCell.self)
|
||||
resultsTableView.registerNib(cellClass: SearchCommonCell.self)
|
||||
resultsTableView.dataSource = self
|
||||
resultsTableView.delegate = self
|
||||
resultsTableView.keyboardDismissMode = .onDrag
|
||||
}
|
||||
|
||||
private func setupHistoryAndCategoryTabView() {
|
||||
historyAndCategoryTabViewController.delegate = self
|
||||
}
|
||||
|
||||
// TODO: (KK) Implement filters collection viewe
|
||||
private func setupFiltersCollectionView() {
|
||||
filtersCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "FilterCell")
|
||||
filtersCollectionView.dataSource = self
|
||||
}
|
||||
|
||||
private func layoutViews() {
|
||||
view.addSubview(headerView)
|
||||
view.addSubview(containerView)
|
||||
headerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
headerView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
|
||||
containerView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
|
||||
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
|
||||
layoutResultsView()
|
||||
layoutHistoryAndCategoryTabView()
|
||||
layoutSearchNoResultsView()
|
||||
layoutSearchingView()
|
||||
}
|
||||
|
||||
private func layoutResultsView() {
|
||||
containerView.addSubview(resultsTableView)
|
||||
resultsTableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
resultsTableView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||
resultsTableView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||
resultsTableView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||
resultsTableView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func layoutHistoryAndCategoryTabView() {
|
||||
containerView.addSubview(historyAndCategoryTabViewController.view)
|
||||
historyAndCategoryTabViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
historyAndCategoryTabViewController.view.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||
historyAndCategoryTabViewController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||
historyAndCategoryTabViewController.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||
historyAndCategoryTabViewController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func layoutSearchNoResultsView() {
|
||||
searchNoResultsView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerView.addSubview(searchNoResultsView)
|
||||
NSLayoutConstraint.activate([
|
||||
searchNoResultsView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||
searchNoResultsView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||
searchNoResultsView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||
searchNoResultsView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func layoutSearchingView() {
|
||||
containerView.insertSubview(searchingActivityView, at: 0)
|
||||
searchingActivityView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
searchingActivityView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||
searchingActivityView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||
searchingActivityView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||
searchingActivityView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
// MARK: - Handle Button Actions
|
||||
@objc private func handleTapOutside(_ gesture: UITapGestureRecognizer) {
|
||||
let location = gesture.location(in: view)
|
||||
if resultsTableView.frame.contains(location) && searchResults.isEmpty {
|
||||
headerView.setIsSearching(false)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Handle State Updates
|
||||
private func setContent(_ content: ContentState) {
|
||||
switch content {
|
||||
case .historyAndCategory:
|
||||
historyAndCategoryTabViewController.reloadSearchHistory()
|
||||
case let .results(results):
|
||||
if searchResults != results {
|
||||
searchResults = results
|
||||
resultsTableView.reloadData()
|
||||
}
|
||||
case .noResults:
|
||||
searchResults = .empty
|
||||
resultsTableView.reloadData()
|
||||
case .searching:
|
||||
break
|
||||
}
|
||||
showView(viewToShow(for: content))
|
||||
}
|
||||
|
||||
private func viewToShow(for content: ContentState) -> UIView {
|
||||
switch content {
|
||||
case .historyAndCategory:
|
||||
return historyAndCategoryTabViewController.view
|
||||
case .results:
|
||||
return resultsTableView
|
||||
case .noResults:
|
||||
return searchNoResultsView
|
||||
case .searching:
|
||||
return searchingActivityView
|
||||
}
|
||||
}
|
||||
|
||||
private func showView(_ view: UIView) {
|
||||
let viewsToHide: [UIView] = [resultsTableView,
|
||||
historyAndCategoryTabViewController.view,
|
||||
searchNoResultsView,
|
||||
searchingActivityView].filter { $0 != view }
|
||||
UIView.transition(with: containerView,
|
||||
duration: kDefaultAnimationDuration / 2,
|
||||
options: [.transitionCrossDissolve, .curveEaseInOut], animations: {
|
||||
viewsToHide.forEach { viewToHide in
|
||||
view.isHidden = false
|
||||
view.alpha = 1
|
||||
viewToHide.isHidden = true
|
||||
viewToHide.alpha = 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func setIsSearching(_ isSearching: Bool) {
|
||||
headerView.setIsSearching(isSearching)
|
||||
}
|
||||
|
||||
private func replaceSearchText(with text: String) {
|
||||
headerView.setSearchText(text)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
extension SearchOnMapViewController: SearchOnMapView {
|
||||
func render(_ viewModel: ViewModel) {
|
||||
setContent(viewModel.contentState)
|
||||
setIsSearching(viewModel.isTyping)
|
||||
if let searchingText = viewModel.searchingText {
|
||||
replaceSearchText(with: searchingText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ModallyPresentedViewController
|
||||
extension SearchOnMapViewController: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
self.containerModalYTranslation = translationY
|
||||
resultsTableView.contentInset.bottom = translationY
|
||||
historyAndCategoryTabViewController.translationYDidUpdate(translationY)
|
||||
searchNoResultsView.translationYDidUpdate(translationY)
|
||||
searchingActivityView.translationYDidUpdate(translationY)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
extension SearchOnMapViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
searchResults.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let result = searchResults[indexPath.row]
|
||||
switch result.itemType {
|
||||
case .regular:
|
||||
let cell = tableView.dequeueReusableCell(cell: SearchCommonCell.self, indexPath: indexPath)
|
||||
cell.configure(with: result, isPartialMatching: searchResults.hasPartialMatch)
|
||||
return cell
|
||||
case .suggestion:
|
||||
let cell = tableView.dequeueReusableCell(cell: SearchSuggestionCell.self, indexPath: indexPath)
|
||||
cell.configure(with: result, isPartialMatching: true)
|
||||
cell.isLastCell = indexPath.row == searchResults.suggestionsCount - 1
|
||||
return cell
|
||||
@unknown default:
|
||||
fatalError("Unknown item type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
extension SearchOnMapViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let result = searchResults[indexPath.row]
|
||||
interactor.handle(.didSelectResult(result, atIndex: indexPath.row, withSearchText: headerView.searchText))
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||
interactor.handle(.didStartDraggingSearch)
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
scrollViewDelegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDataSource
|
||||
extension SearchOnMapViewController: UICollectionViewDataSource {
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
// TODO: remove search from here
|
||||
Int(Search.resultsCount())
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCell", for: indexPath)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SearchOnMapHeaderViewDelegate
|
||||
extension SearchOnMapViewController: SearchOnMapHeaderViewDelegate {
|
||||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
interactor.handle(.didStartTyping)
|
||||
}
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||||
guard !searchText.isEmpty else {
|
||||
interactor.handle(.clearButtonDidTap)
|
||||
return
|
||||
}
|
||||
interactor.handle(.didType(SearchText(searchText, locale: searchBar.textInputMode?.primaryLanguage)))
|
||||
}
|
||||
|
||||
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
|
||||
guard let searchText = searchBar.text, !searchText.isEmpty else { return }
|
||||
interactor.handle(.searchButtonDidTap(SearchText(searchText, locale: searchBar.textInputMode?.primaryLanguage)))
|
||||
}
|
||||
|
||||
func cancelButtonDidTap() {
|
||||
interactor.handle(.closeSearch)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SearchTabViewControllerDelegate
|
||||
extension SearchOnMapViewController: SearchTabViewControllerDelegate {
|
||||
func searchTabController(_ viewController: SearchTabViewController, didSearch text: String, withCategory: Bool) {
|
||||
interactor.handle(.didSelectText(SearchText(text, locale: nil), isCategory: withCategory))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
class SearchTextField: UITextField {
|
||||
override func drawPlaceholder(in rect: CGRect) {
|
||||
guard let font = font, let tint = tintColor else {
|
||||
super.drawPlaceholder(in: rect);
|
||||
return
|
||||
}
|
||||
placeholder?.draw(
|
||||
in: rect,
|
||||
withAttributes: [
|
||||
NSAttributedString.Key.font: font,
|
||||
NSAttributedString.Key.foregroundColor: tint
|
||||
])
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
for view in subviews {
|
||||
if (view is UIButton) {
|
||||
let button = view as? UIButton
|
||||
let clearButtonImage: UIImage?
|
||||
if #available(iOS 13.0, *) {
|
||||
clearButtonImage = UIImage(named: "ic_clear")?.withRenderingMode(.alwaysTemplate).withTintColor(tintColor)
|
||||
} else {
|
||||
clearButtonImage = UIImage(named: "ic_search_clear_14")
|
||||
}
|
||||
button?.setImage(clearButtonImage, for: .normal)
|
||||
button?.tintColor = tintColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
@interface MWMSearchTableView : UIView
|
||||
|
||||
- (void)hideNoResultsView:(BOOL)hide;
|
||||
|
||||
@end
|
|
@ -1,71 +0,0 @@
|
|||
#import "MWMSearchTableView.h"
|
||||
#import "MWMKeyboard.h"
|
||||
#import "MWMSearchNoResults.h"
|
||||
|
||||
@interface MWMSearchTableView ()<MWMKeyboardObserver>
|
||||
|
||||
@property(weak, nonatomic) IBOutlet NSLayoutConstraint * noResultsBottomOffset;
|
||||
|
||||
@property(weak, nonatomic) IBOutlet UIView * noResultsContainer;
|
||||
@property(weak, nonatomic) IBOutlet UIView * noResultsWrapper;
|
||||
@property(nonatomic) MWMSearchNoResults * noResultsView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSearchTableView
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
CALayer * sl = self.layer;
|
||||
sl.shouldRasterize = YES;
|
||||
sl.rasterizationScale = UIScreen.mainScreen.scale;
|
||||
[MWMKeyboard addObserver:self];
|
||||
}
|
||||
|
||||
- (void)hideNoResultsView:(BOOL)hide
|
||||
{
|
||||
if (hide)
|
||||
{
|
||||
self.noResultsContainer.hidden = YES;
|
||||
[self.noResultsView removeFromSuperview];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.noResultsContainer.hidden = NO;
|
||||
[self.noResultsWrapper addSubview:self.noResultsView];
|
||||
[self onKeyboardAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MWMKeyboard
|
||||
|
||||
- (void)onKeyboardAnimation
|
||||
{
|
||||
CGFloat const keyboardHeight = [MWMKeyboard keyboardHeight];
|
||||
if (keyboardHeight >= self.height)
|
||||
return;
|
||||
|
||||
self.noResultsBottomOffset.constant = keyboardHeight;
|
||||
if (self.superview)
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)onKeyboardWillAnimate
|
||||
{
|
||||
if (self.superview)
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (MWMSearchNoResults *)noResultsView
|
||||
{
|
||||
if (!_noResultsView)
|
||||
{
|
||||
_noResultsView = [MWMSearchNoResults viewWithImage:nil
|
||||
title:L(@"search_not_found")
|
||||
text:L(@"search_not_found_query")];
|
||||
}
|
||||
return _noResultsView;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,27 +0,0 @@
|
|||
#import "MWMSearch.h"
|
||||
#import "MWMSearchManager.h"
|
||||
#import "MWMSearchTabbedViewProtocol.h"
|
||||
#import "MWMViewController.h"
|
||||
|
||||
#include <CoreApi/Framework.h>
|
||||
|
||||
@class SearchTextField;
|
||||
|
||||
@protocol MWMSearchTableViewProtocol<MWMSearchTabbedViewProtocol>
|
||||
|
||||
@property(nullable, weak, nonatomic) SearchTextField * searchTextField;
|
||||
|
||||
@property(nonatomic) MWMSearchManagerState state;
|
||||
|
||||
- (void)processSearchResultAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMSearchTableViewController : MWMViewController<MWMSearchObserver>
|
||||
|
||||
- (nonnull instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (nonnull instancetype)initWithDelegate:(nonnull id<MWMSearchTableViewProtocol>)delegate;
|
||||
|
||||
- (void)reloadData;
|
||||
|
||||
@end
|
|
@ -1,143 +0,0 @@
|
|||
#import "MWMSearchTableViewController.h"
|
||||
#import "MWMSearchCommonCell.h"
|
||||
#import "MWMSearchSuggestionCell.h"
|
||||
#import "MWMSearchTableView.h"
|
||||
#import "SearchResult.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
#include "platform/localization.hpp"
|
||||
|
||||
#include "search/result.hpp"
|
||||
|
||||
namespace {
|
||||
NSString *GetLocalizedTypeName(search::Result const &result) {
|
||||
return @(result.GetLocalizedFeatureType().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@interface MWMSearchTableViewController () <UITableViewDataSource, UITableViewDelegate>
|
||||
|
||||
@property(weak, nonatomic) IBOutlet UITableView *tableView;
|
||||
|
||||
@property(weak, nonatomic) id<MWMSearchTableViewProtocol> delegate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSearchTableViewController
|
||||
|
||||
- (nonnull instancetype)initWithDelegate:(id<MWMSearchTableViewProtocol>)delegate {
|
||||
self = [super init];
|
||||
if (self)
|
||||
_delegate = delegate;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self setupTableView];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.tableView.hidden = NO;
|
||||
self.tableView.insetsContentViewsToSafeArea = YES;
|
||||
[(MWMSearchTableView *)self.view hideNoResultsView:YES];
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
- (void)setupTableView {
|
||||
UITableView *tableView = self.tableView;
|
||||
tableView.estimatedRowHeight = 80.;
|
||||
tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
[tableView registerNibWithCellClass:[MWMSearchSuggestionCell class]];
|
||||
[tableView registerNibWithCellClass:[MWMSearchCommonCell class]];
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
#pragma mark - Layout
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[coordinator
|
||||
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||
[self reloadData];
|
||||
}
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return [MWMSearch resultsCount];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if ([MWMSearch resultsCount] == 0) {
|
||||
NSAssert(false, @"Invalid reload with outdated SearchIndex");
|
||||
return [tableView dequeueReusableCellWithCellClass:[MWMSearchCommonCell class] indexPath:indexPath];
|
||||
}
|
||||
|
||||
auto const row = indexPath.row;
|
||||
auto const containerIndex = [MWMSearch containerIndexWithRow:row];
|
||||
auto const & result = [MWMSearch resultWithContainerIndex:containerIndex];
|
||||
|
||||
switch ([MWMSearch resultTypeWithRow:row])
|
||||
{
|
||||
case SearchItemTypeRegular:
|
||||
{
|
||||
auto cell = static_cast<MWMSearchCommonCell *>(
|
||||
[tableView dequeueReusableCellWithCellClass:[MWMSearchCommonCell class] indexPath:indexPath]);
|
||||
[cell configureWith:result isPartialMatching:YES];
|
||||
return cell;
|
||||
}
|
||||
case SearchItemTypeSuggestion:
|
||||
{
|
||||
auto cell = static_cast<MWMSearchSuggestionCell *>(
|
||||
[tableView dequeueReusableCellWithCellClass:[MWMSearchSuggestionCell class] indexPath:indexPath]);
|
||||
[cell configureWith:result isPartialMatching:YES];
|
||||
cell.isLastCell = row == [MWMSearch suggestionsCount] - 1;
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
id<MWMSearchTableViewProtocol> delegate = self.delegate;
|
||||
auto const row = indexPath.row;
|
||||
auto const containerIndex = [MWMSearch containerIndexWithRow:row];
|
||||
auto const & result = [MWMSearch resultWithContainerIndex:containerIndex];
|
||||
|
||||
switch ([MWMSearch resultTypeWithRow:row])
|
||||
{
|
||||
case SearchItemTypeRegular:
|
||||
{
|
||||
SearchTextField const * textField = delegate.searchTextField;
|
||||
[MWMSearch saveQuery:textField.text forInputLocale:textField.textInputMode.primaryLanguage];
|
||||
[delegate processSearchResultAtIndex:indexPath.row];
|
||||
break;
|
||||
}
|
||||
case SearchItemTypeSuggestion:
|
||||
{
|
||||
[delegate searchText:result.suggestion
|
||||
forInputLocale:nil
|
||||
withCategory:result.isPureSuggest];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MWMSearchObserver
|
||||
|
||||
- (void)onSearchCompleted {
|
||||
[self reloadData];
|
||||
BOOL const noResults = [MWMSearch resultsCount] == 0;
|
||||
self.tableView.hidden = noResults;
|
||||
[(MWMSearchTableView *)self.view hideNoResultsView:!noResults];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,79 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMSearchTableViewController">
|
||||
<connections>
|
||||
<outlet property="tableView" destination="oZD-Er-6fn" id="Ayl-9n-mV7"/>
|
||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" id="i5M-Pr-FkT" customClass="MWMSearchTableView" propertyAccessControl="none">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NsS-9j-1hr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0ed-oS-Uw6">
|
||||
<rect key="frame" x="0.0" y="70" width="320" height="320"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="320" id="iu3-jC-BuA"/>
|
||||
<constraint firstAttribute="width" secondItem="0ed-oS-Uw6" secondAttribute="height" multiplier="1:1" priority="999" id="rBn-RY-c74"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="0ed-oS-Uw6" firstAttribute="centerY" secondItem="NsS-9j-1hr" secondAttribute="centerY" id="3os-g7-XiN"/>
|
||||
<constraint firstItem="0ed-oS-Uw6" firstAttribute="centerX" secondItem="NsS-9j-1hr" secondAttribute="centerX" id="N4N-MH-XVw"/>
|
||||
<constraint firstItem="0ed-oS-Uw6" firstAttribute="height" relation="lessThanOrEqual" secondItem="NsS-9j-1hr" secondAttribute="height" id="aad-2C-r3O"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="oZD-Er-6fn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<inset key="separatorInset" minX="15" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-1" id="T9n-AG-sHf"/>
|
||||
<outlet property="delegate" destination="-1" id="Syl-wX-U5b"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="oZD-Er-6fn" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="9cU-AY-lQv"/>
|
||||
<constraint firstItem="NsS-9j-1hr" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="C7g-sy-qp4"/>
|
||||
<constraint firstAttribute="trailing" secondItem="oZD-Er-6fn" secondAttribute="trailing" id="DoP-hv-QXb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="NsS-9j-1hr" secondAttribute="bottom" priority="750" id="P9i-5E-bpw"/>
|
||||
<constraint firstItem="NsS-9j-1hr" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="csW-fl-Sp0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="NsS-9j-1hr" secondAttribute="trailing" id="dIC-Mf-12H"/>
|
||||
<constraint firstItem="oZD-Er-6fn" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="iKy-dd-6Jt"/>
|
||||
<constraint firstAttribute="bottom" secondItem="oZD-Er-6fn" secondAttribute="bottom" priority="750" id="rgu-oY-7XC"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="noResultsBottomOffset" destination="P9i-5E-bpw" id="qTI-X5-KzS"/>
|
||||
<outlet property="noResultsContainer" destination="NsS-9j-1hr" id="BfV-Wz-ztf"/>
|
||||
<outlet property="noResultsWrapper" destination="0ed-oS-Uw6" id="RbW-yn-sl8"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="139" y="154"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
|
@ -1,4 +1,4 @@
|
|||
protocol SearchCategoriesViewControllerDelegate: AnyObject {
|
||||
protocol SearchCategoriesViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func categoriesViewController(_ viewController: SearchCategoriesViewController,
|
||||
didSelect category: String)
|
||||
}
|
||||
|
@ -41,8 +41,19 @@ final class SearchCategoriesViewController: MWMTableViewController {
|
|||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
|
||||
func category(at indexPath: IndexPath) -> String {
|
||||
let index = indexPath.row
|
||||
return categories[index]
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchCategoriesViewController: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
guard isViewLoaded else { return }
|
||||
tableView.contentInset.bottom = translationY + view.safeAreaInsets.bottom
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,97 @@
|
|||
protocol SearchHistoryViewControllerDelegate: AnyObject {
|
||||
protocol SearchHistoryViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func searchHistoryViewController(_ viewController: SearchHistoryViewController,
|
||||
didSelect query: String)
|
||||
}
|
||||
|
||||
final class SearchHistoryViewController: MWMViewController {
|
||||
private weak var delegate: SearchHistoryViewControllerDelegate?
|
||||
private var lastQueries: [String]
|
||||
private var lastQueries: [String] = []
|
||||
private let frameworkHelper: MWMSearchFrameworkHelper
|
||||
private static let clearCellIdentifier = "SearchHistoryViewController_clearCellIdentifier"
|
||||
|
||||
@IBOutlet private var tableView: UITableView!
|
||||
@IBOutlet private weak var noResultsViewContainer: UIView!
|
||||
|
||||
private let emptyHistoryView = PlaceholderView(title: L("search_history_title"),
|
||||
subtitle: L("search_history_text"))
|
||||
|
||||
private let tableView = UITableView()
|
||||
|
||||
// MARK: - Init
|
||||
init(frameworkHelper: MWMSearchFrameworkHelper, delegate: SearchHistoryViewControllerDelegate?) {
|
||||
self.delegate = delegate
|
||||
self.lastQueries = frameworkHelper.lastSearchQueries()
|
||||
self.frameworkHelper = frameworkHelper
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Lifecycle
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
if frameworkHelper.isSearchHistoryEmpty() {
|
||||
showNoResultsView()
|
||||
} else {
|
||||
tableView.register(cell: SearchHistoryCell.self)
|
||||
}
|
||||
setupTableView()
|
||||
setupNoResultsView()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
reload()
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupTableView() {
|
||||
tableView.setStyle(.background)
|
||||
tableView.register(cell: SearchHistoryCell.self)
|
||||
tableView.keyboardDismissMode = .onDrag
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 1))
|
||||
|
||||
view.addSubview(tableView)
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
func showNoResultsView() {
|
||||
guard let noResultsView = MWMSearchNoResults.view(with: nil,
|
||||
title: L("search_history_title"),
|
||||
text: L("search_history_text")) else {
|
||||
assertionFailure()
|
||||
return
|
||||
|
||||
private func setupNoResultsView() {
|
||||
view.addSubview(emptyHistoryView)
|
||||
emptyHistoryView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
emptyHistoryView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
emptyHistoryView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
emptyHistoryView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
emptyHistoryView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func showEmptyHistoryView(_ isVisible: Bool = true, animated: Bool = true) {
|
||||
UIView.transition(with: emptyHistoryView,
|
||||
duration: animated ? kDefaultAnimationDuration : 0,
|
||||
options: [.transitionCrossDissolve, .curveEaseInOut]) {
|
||||
self.emptyHistoryView.alpha = isVisible ? 1.0 : 0.0
|
||||
self.emptyHistoryView.isHidden = !isVisible
|
||||
}
|
||||
noResultsViewContainer.addSubview(noResultsView)
|
||||
tableView.isHidden = true
|
||||
}
|
||||
|
||||
func clearSearchHistory() {
|
||||
private func clearSearchHistory() {
|
||||
frameworkHelper.clearSearchHistory()
|
||||
lastQueries = []
|
||||
reload()
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
func reload() {
|
||||
guard isViewLoaded else { return }
|
||||
lastQueries = frameworkHelper.lastSearchQueries()
|
||||
showEmptyHistoryView(lastQueries.isEmpty ? true : false)
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchHistoryViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return frameworkHelper.isSearchHistoryEmpty() ? 0 : lastQueries.count + 1
|
||||
return lastQueries.isEmpty ? 0 : lastQueries.count + 1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
@ -71,16 +109,22 @@ extension SearchHistoryViewController: UITableViewDelegate {
|
|||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
if indexPath.row == lastQueries.count {
|
||||
clearSearchHistory()
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration,
|
||||
animations: {
|
||||
tableView.alpha = 0.0
|
||||
}) { _ in
|
||||
self.showNoResultsView()
|
||||
}
|
||||
} else {
|
||||
let query = lastQueries[indexPath.row]
|
||||
delegate?.searchHistoryViewController(self, didSelect: query)
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchHistoryViewController: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
guard isViewLoaded else { return }
|
||||
tableView.contentInset.bottom = translationY
|
||||
emptyHistoryView.translationYDidUpdate(translationY)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SearchHistoryViewController" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="noResultsViewContainer" destination="bcr-zs-NMw" id="zpc-sP-fbF"/>
|
||||
<outlet property="tableView" destination="cDq-G7-5cR" id="Qo8-a6-Q6V"/>
|
||||
<outlet property="view" destination="iN0-l3-epB" id="Ybt-gX-7O4"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="cDq-G7-5cR">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-1" id="XhM-2x-4kQ"/>
|
||||
<outlet property="delegate" destination="-1" id="sDX-YJ-iGy"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bcr-zs-NMw">
|
||||
<rect key="frame" x="27.5" y="183.5" width="320" height="320"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="320" id="07E-Xc-KMw"/>
|
||||
<constraint firstAttribute="width" constant="320" id="sCQ-Q9-Pdw"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="cDq-G7-5cR" secondAttribute="bottom" id="9QA-Kd-FQb"/>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="cDq-G7-5cR" secondAttribute="trailing" id="T3b-23-qG6"/>
|
||||
<constraint firstItem="bcr-zs-NMw" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="Y7z-3L-jl5"/>
|
||||
<constraint firstItem="cDq-G7-5cR" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="ezl-g4-mlD"/>
|
||||
<constraint firstItem="cDq-G7-5cR" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="ot8-FU-S6n"/>
|
||||
<constraint firstItem="bcr-zs-NMw" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="uMb-A3-NrS"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<point key="canvasLocation" x="53.600000000000001" y="48.125937031484263"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
|
@ -1,12 +0,0 @@
|
|||
#import "MWMSearchManagerState.h"
|
||||
|
||||
@protocol MWMSearchTabbedViewProtocol <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
@property(nonatomic) MWMSearchManagerState state;
|
||||
|
||||
- (void)searchText:(NSString *)text forInputLocale:(NSString *)locale withCategory:(BOOL)isCategory;
|
||||
- (void)dismissKeyboard;
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
@objc(MWMSearchTabViewControllerDelegate)
|
||||
protocol SearchTabViewControllerDelegate: AnyObject {
|
||||
protocol SearchTabViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func searchTabController(_ viewController: SearchTabViewController, didSearch: String, withCategory: Bool)
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,22 @@ final class SearchTabViewController: TabViewController {
|
|||
super.viewDidDisappear(animated)
|
||||
activeTab = SearchActiveTab.init(rawValue: tabView.selectedIndex ?? 0) ?? .categories
|
||||
}
|
||||
|
||||
func reloadSearchHistory() {
|
||||
(viewControllers[SearchActiveTab.history.rawValue] as? SearchHistoryViewController)?.reload()
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: ModallyPresentedViewController {
|
||||
func translationYDidUpdate(_ translationY: CGFloat) {
|
||||
viewControllers.forEach { ($0 as? ModallyPresentedViewController)?.translationYDidUpdate(translationY) }
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: SearchOnMapScrollViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: SearchCategoriesViewControllerDelegate {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Wns-nH-AQU">
|
||||
<device id="retina6_72" orientation="landscape" appearance="light"/>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Wns-nH-AQU">
|
||||
<device id="iPad13_0rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
|
@ -14,26 +14,26 @@
|
|||
<objects>
|
||||
<viewController id="xTf-lf-yxN" customClass="MapViewController" sceneMemberID="viewController">
|
||||
<view key="view" clearsContextBeforeDrawing="NO" multipleTouchEnabled="YES" contentMode="scaleToFill" id="USG-6L-Uhw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ixC-IZ-Pvs" userLabel="CarPlayPlaceholderView" customClass="CarplayPlaceholderView" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aPn-pa-nCx" customClass="EAGLView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<color key="backgroundColor" red="0.8666666666666667" green="0.8666666666666667" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rL1-9E-4b7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<subviews>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="65S-M4-TnM" customClass="NavigationInfoArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1332"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TdT-ia-GP9">
|
||||
<rect key="frame" x="59" y="0.0" width="350" height="409"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1356"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="350" id="XLL-zv-Bym"/>
|
||||
|
@ -50,7 +50,7 @@
|
|||
</variation>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aVk-ab-LFJ" customClass="TabBarArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="361" width="350" height="69"/>
|
||||
<rect key="frame" x="0.0" y="1308" width="1032" height="68"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" priority="100" constant="350" id="aj4-lb-h52"/>
|
||||
|
@ -67,26 +67,26 @@
|
|||
</variation>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="awj-9E-eBS" customClass="PlacePageArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1356"/>
|
||||
<color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FFY-Dy-Wou" customClass="VisibleArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1356"/>
|
||||
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NI8-tV-i2B" customClass="WidgetsArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1332"/>
|
||||
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xJx-UU-IdV" customClass="SideButtonsArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1332"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="1" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QKu-4A-UgP" customClass="TrafficButtonArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1332"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yto-Gu-Ugz" userLabel="Track Recording Button Area" customClass="TrackRecordingButtonArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="59" width="430" height="839"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1332"/>
|
||||
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
|
@ -98,64 +98,8 @@
|
|||
<constraint firstItem="FFY-Dy-Wou" firstAttribute="top" secondItem="rL1-9E-4b7" secondAttribute="top" priority="100" id="svT-Vi-vvC"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" placeholderIntrinsicWidth="infinite" placeholderIntrinsicHeight="500" translatesAutoresizingMaskIntoConstraints="NO" id="jio-3T-E6G" customClass="TouchTransparentView" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="350" height="430"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="350" id="Dd0-x6-7gc">
|
||||
<variation key="heightClass=regular-widthClass=regular" constant="320"/>
|
||||
</constraint>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="Dd0-x6-7gc"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="Dd0-x6-7gc"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="Dd0-x6-7gc"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="Dd0-x6-7gc"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" placeholderIntrinsicWidth="infinite" placeholderIntrinsicHeight="500" translatesAutoresizingMaskIntoConstraints="NO" id="rbx-Oj-jeo" customClass="TouchTransparentView" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="350" height="430"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="350" id="6h8-a6-LWn"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="6h8-a6-LWn"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="6h8-a6-LWn"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="6h8-a6-LWn"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="6h8-a6-LWn"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="at1-V1-pzl" customClass="TouchTransparentView" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="209" width="814" height="152"/>
|
||||
<rect key="frame" x="0.0" y="722" width="440" height="152"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
|
@ -171,14 +115,11 @@
|
|||
<constraints>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="65S-M4-TnM" secondAttribute="bottom" priority="100" id="2E3-5i-6An"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rL1-9E-4b7" secondAttribute="bottom" id="4fw-Xu-gAG"/>
|
||||
<constraint firstItem="rbx-Oj-jeo" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="5Sh-l6-Icd"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="QKu-4A-UgP" secondAttribute="bottom" priority="100" id="6ko-rI-S5u"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ixC-IZ-Pvs" secondAttribute="bottom" id="7eh-og-Mpe"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="aVk-ab-LFJ" secondAttribute="trailing" id="85b-Do-jO7"/>
|
||||
<constraint firstItem="at1-V1-pzl" firstAttribute="top" secondItem="utd-Jy-pE5" secondAttribute="bottom" priority="250" id="8JV-dP-iYZ"/>
|
||||
<constraint firstItem="TdT-ia-GP9" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="8YH-dJ-lHZ"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="rbx-Oj-jeo" secondAttribute="trailing" id="9M9-8P-Hzb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rbx-Oj-jeo" secondAttribute="bottom" id="9rR-QQ-c1P"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="xJx-UU-IdV" secondAttribute="top" priority="100" id="BMq-jc-qfO"/>
|
||||
<constraint firstItem="ixC-IZ-Pvs" firstAttribute="top" secondItem="USG-6L-Uhw" secondAttribute="top" id="DSJ-0D-hwO"/>
|
||||
<constraint firstItem="rL1-9E-4b7" firstAttribute="top" secondItem="USG-6L-Uhw" secondAttribute="top" id="E89-WV-ZTh"/>
|
||||
|
@ -187,8 +128,6 @@
|
|||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="at1-V1-pzl" secondAttribute="trailing" id="GKG-4Y-2Pq"/>
|
||||
<constraint firstAttribute="trailing" secondItem="aPn-pa-nCx" secondAttribute="trailing" id="GKJ-zm-8xb"/>
|
||||
<constraint firstItem="awj-9E-eBS" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="Hfm-gb-37H"/>
|
||||
<constraint firstItem="rbx-Oj-jeo" firstAttribute="top" secondItem="utd-Jy-pE5" secondAttribute="top" id="J0B-xe-sNj"/>
|
||||
<constraint firstItem="jio-3T-E6G" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="K9r-P1-yFI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ixC-IZ-Pvs" secondAttribute="trailing" id="O7f-qU-UN2"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="at1-V1-pzl" secondAttribute="bottom" priority="750" constant="48" id="O8L-nd-nOa"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="FFY-Dy-Wou" secondAttribute="bottom" priority="100" id="OE7-Qb-J0v"/>
|
||||
|
@ -196,13 +135,11 @@
|
|||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="awj-9E-eBS" secondAttribute="bottom" id="PFs-sL-oVA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rL1-9E-4b7" secondAttribute="trailing" id="QdS-Yx-ADV"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="TdT-ia-GP9" secondAttribute="trailing" id="Rsb-fB-8bn"/>
|
||||
<constraint firstItem="jio-3T-E6G" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" constant="-320" id="SAj-bF-qrr"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="xJx-UU-IdV" secondAttribute="bottom" id="SDX-4J-Jz5"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="FFY-Dy-Wou" secondAttribute="bottom" id="TZk-MH-pMV"/>
|
||||
<constraint firstItem="yto-Gu-Ugz" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="TgS-dg-g9B"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="yto-Gu-Ugz" secondAttribute="trailing" id="URB-3l-JiC"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="xJx-UU-IdV" secondAttribute="bottom" priority="100" id="VfU-Zk-8IU"/>
|
||||
<constraint firstItem="rbx-Oj-jeo" firstAttribute="leading" secondItem="jio-3T-E6G" secondAttribute="trailing" constant="20" id="W0l-NG-7lt"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="QKu-4A-UgP" secondAttribute="top" priority="100" id="X96-y7-5oI"/>
|
||||
<constraint firstItem="aPn-pa-nCx" firstAttribute="leading" secondItem="USG-6L-Uhw" secondAttribute="leading" id="YFX-ma-vAf"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="FFY-Dy-Wou" secondAttribute="bottom" id="YUs-MJ-9w8"/>
|
||||
|
@ -217,18 +154,14 @@
|
|||
<constraint firstItem="xJx-UU-IdV" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="gn8-NV-oAa"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="aVk-ab-LFJ" secondAttribute="top" priority="100" constant="48" id="jQI-62-O5O"/>
|
||||
<constraint firstItem="65S-M4-TnM" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="kan-ei-cIg"/>
|
||||
<constraint firstAttribute="bottom" secondItem="jio-3T-E6G" secondAttribute="bottom" id="l6r-eW-Dbi"/>
|
||||
<constraint firstItem="NI8-tV-i2B" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="lwX-Xm-J8A"/>
|
||||
<constraint firstItem="ixC-IZ-Pvs" firstAttribute="leading" secondItem="USG-6L-Uhw" secondAttribute="leading" id="m7B-SH-DDh"/>
|
||||
<constraint firstItem="FFY-Dy-Wou" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="pc3-CW-vyV"/>
|
||||
<constraint firstItem="aPn-pa-nCx" firstAttribute="top" secondItem="USG-6L-Uhw" secondAttribute="top" id="pwE-hX-IML"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="TdT-ia-GP9" secondAttribute="bottom" priority="100" id="pwZ-Fm-mHR"/>
|
||||
<constraint firstItem="aVk-ab-LFJ" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="qtc-CV-Hae"/>
|
||||
<constraint firstAttribute="top" secondItem="jio-3T-E6G" secondAttribute="top" id="rYG-px-wH5"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="NI8-tV-i2B" secondAttribute="top" priority="100" id="sSU-QE-9zI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jio-3T-E6G" secondAttribute="trailing" id="t9l-Ud-h6j"/>
|
||||
<constraint firstAttribute="bottom" secondItem="aPn-pa-nCx" secondAttribute="bottom" id="tB3-eX-gUV"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="rbx-Oj-jeo" secondAttribute="bottom" constant="70" id="u9s-KY-yCt"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="xJx-UU-IdV" secondAttribute="bottom" id="veF-Rn-BEm"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="65S-M4-TnM" secondAttribute="top" priority="100" id="vfQ-ZT-Dlc"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="awj-9E-eBS" secondAttribute="trailing" id="wGo-EW-X9f"/>
|
||||
|
@ -240,10 +173,6 @@
|
|||
<exclude reference="SDX-4J-Jz5"/>
|
||||
<exclude reference="TZk-MH-pMV"/>
|
||||
<exclude reference="veF-Rn-BEm"/>
|
||||
<exclude reference="u9s-KY-yCt"/>
|
||||
<exclude reference="K9r-P1-yFI"/>
|
||||
<exclude reference="SAj-bF-qrr"/>
|
||||
<exclude reference="W0l-NG-7lt"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact">
|
||||
|
@ -252,7 +181,6 @@
|
|||
<exclude reference="Rsb-fB-8bn"/>
|
||||
<include reference="TZk-MH-pMV"/>
|
||||
<include reference="veF-Rn-BEm"/>
|
||||
<include reference="K9r-P1-yFI"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular">
|
||||
|
@ -260,34 +188,6 @@
|
|||
<include reference="SDX-4J-Jz5"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="widthClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="K9r-P1-yFI"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=compact">
|
||||
<mask key="constraints">
|
||||
<exclude reference="9M9-8P-Hzb"/>
|
||||
<exclude reference="t9l-Ud-h6j"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<exclude reference="9M9-8P-Hzb"/>
|
||||
<exclude reference="t9l-Ud-h6j"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<exclude reference="9M9-8P-Hzb"/>
|
||||
<include reference="u9s-KY-yCt"/>
|
||||
<exclude reference="t9l-Ud-h6j"/>
|
||||
<include reference="SAj-bF-qrr"/>
|
||||
<exclude reference="9rR-QQ-c1P"/>
|
||||
<include reference="W0l-NG-7lt"/>
|
||||
<exclude reference="5Sh-l6-Icd"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="8E8-0f-UV9"/>
|
||||
<connections>
|
||||
|
@ -295,9 +195,6 @@
|
|||
<outlet property="controlsView" destination="rL1-9E-4b7" id="sfV-7X-WlR"/>
|
||||
<outlet property="mapView" destination="aPn-pa-nCx" id="tCi-LW-1ll"/>
|
||||
<outlet property="placePageAreaKeyboard" destination="PFs-sL-oVA" id="O3P-ia-ZlX"/>
|
||||
<outlet property="placePageContainer" destination="rbx-Oj-jeo" id="aFM-qm-QHB"/>
|
||||
<outlet property="searchViewContainer" destination="jio-3T-E6G" id="Rjn-UE-zFx"/>
|
||||
<outlet property="searchViewContainerLeadingConstraint" destination="SAj-bF-qrr" id="LJL-dW-eMM"/>
|
||||
<outlet property="sideButtonsAreaBottom" destination="VfU-Zk-8IU" id="MvP-Ki-4wP"/>
|
||||
<outlet property="sideButtonsAreaKeyboard" destination="SDX-4J-Jz5" id="kv9-zX-hbD"/>
|
||||
<outlet property="visibleAreaBottom" destination="OE7-Qb-J0v" id="isp-aT-LtA"/>
|
||||
|
@ -342,7 +239,7 @@
|
|||
<objects>
|
||||
<tableViewController storyboardIdentifier="MWMEditBookmarkController" id="lFr-lA-JTW" customClass="MWMEditBookmarkController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="Rb3-ea-7LJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
|
@ -362,7 +259,7 @@
|
|||
<navigationController id="Psz-BY-Fy4" customClass="MWMNavigationController" sceneMemberID="viewController">
|
||||
<value key="contentSizeForViewInPopover" type="size" width="600" height="600"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="SUN-3A-xgM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
@ -378,7 +275,7 @@
|
|||
<objects>
|
||||
<tableViewController id="Lfa-Zp-orR" customClass="MWMEditorViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="HU6-ak-Eu1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
|
@ -404,11 +301,11 @@
|
|||
<objects>
|
||||
<viewController id="Ld6-gM-2hk" customClass="MWMOpeningHoursEditorViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="U1f-hD-9rl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="none" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="X1H-IB-Nv1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="365"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1288"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="PressBackground"/>
|
||||
|
@ -419,10 +316,10 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aQv-7U-zAP">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="365"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="1288"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="PrH-u2-IEv" userLabel="Editor View" customClass="MWMTextView">
|
||||
<rect key="frame" x="0.0" y="36" width="814" height="88"/>
|
||||
<rect key="frame" x="0.0" y="36" width="1032" height="88"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="88" id="oAE-yX-hVe"/>
|
||||
|
@ -439,7 +336,7 @@
|
|||
</connections>
|
||||
</textView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="z2Z-G2-Np7">
|
||||
<rect key="frame" x="0.0" y="35" width="814" height="1"/>
|
||||
<rect key="frame" x="0.0" y="35" width="1032" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="xUX-ck-MQb"/>
|
||||
</constraints>
|
||||
|
@ -448,7 +345,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="ebA-fW-ddJ">
|
||||
<rect key="frame" x="0.0" y="123" width="814" height="1"/>
|
||||
<rect key="frame" x="0.0" y="123" width="1032" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="HOj-tZ-b3F"/>
|
||||
</constraints>
|
||||
|
@ -457,7 +354,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="5T5-Pp-hb5">
|
||||
<rect key="frame" x="0.0" y="320" width="814" height="1"/>
|
||||
<rect key="frame" x="0.0" y="1243" width="1032" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="ZXK-zv-uSz"/>
|
||||
</constraints>
|
||||
|
@ -466,7 +363,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="IX2-yp-0oa">
|
||||
<rect key="frame" x="0.0" y="164" width="814" height="1"/>
|
||||
<rect key="frame" x="0.0" y="164" width="1032" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="rD4-fE-ez2"/>
|
||||
</constraints>
|
||||
|
@ -475,13 +372,13 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="85Z-MR-kUV" userLabel="Help View">
|
||||
<rect key="frame" x="0.0" y="164" width="814" height="328"/>
|
||||
<rect key="frame" x="0.0" y="164" width="1032" height="324"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n79-h1-Nk3" userLabel="Button">
|
||||
<rect key="frame" x="0.0" y="0.0" width="814" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="44"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Example values" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="120" translatesAutoresizingMaskIntoConstraints="NO" id="dAM-iT-fzu">
|
||||
<rect key="frame" x="16.000000000000007" y="12" width="117.66666666666669" height="20"/>
|
||||
<rect key="frame" x="16" y="12" width="117.5" height="20"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -491,7 +388,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_arrow_gray_down" translatesAutoresizingMaskIntoConstraints="NO" id="m7d-sG-5LN">
|
||||
<rect key="frame" x="782" y="10" width="24" height="24"/>
|
||||
<rect key="frame" x="1000" y="10" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="24" id="2aF-WV-ER2"/>
|
||||
<constraint firstAttribute="width" constant="24" id="eak-KY-Xaa"/>
|
||||
|
@ -501,7 +398,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="Suj-t5-ZWs">
|
||||
<rect key="frame" x="16" y="44" width="798" height="1"/>
|
||||
<rect key="frame" x="16" y="44" width="1016" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="cv8-Tg-Oin"/>
|
||||
</constraints>
|
||||
|
@ -510,7 +407,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="MiP-Du-s3i">
|
||||
<rect key="frame" x="0.0" y="0.0" width="814" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="44"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<action selector="toggleExample" destination="Ld6-gM-2hk" eventType="touchUpInside" id="BGK-Ap-YBq"/>
|
||||
|
@ -537,7 +434,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<wkWebView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gff-2B-vhp">
|
||||
<rect key="frame" x="10" y="54" width="373" height="260"/>
|
||||
<rect key="frame" x="10" y="54" width="1012" height="260"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" priority="750" constant="260" id="NdE-kI-erk"/>
|
||||
|
@ -587,10 +484,10 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SZQ-ra-FC3" userLabel="Mode Switch">
|
||||
<rect key="frame" x="0.0" y="365" width="932" height="44"/>
|
||||
<rect key="frame" x="0.0" y="1312" width="1032" height="44"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fB1-w2-lJI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="44"/>
|
||||
<inset key="contentEdgeInsets" minX="16" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
<state key="normal" title="Simple Mode"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
|
@ -601,7 +498,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_arrow_gray_right" translatesAutoresizingMaskIntoConstraints="NO" id="z8F-55-5rJ">
|
||||
<rect key="frame" x="900" y="10" width="24" height="24"/>
|
||||
<rect key="frame" x="1000" y="10" width="24" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="ypP-17-bfX"/>
|
||||
<constraint firstAttribute="height" constant="24" id="zE5-1N-qvh"/>
|
||||
|
@ -611,7 +508,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="separator_image" translatesAutoresizingMaskIntoConstraints="NO" id="onT-vv-01i">
|
||||
<rect key="frame" x="0.0" y="-1" width="932" height="1"/>
|
||||
<rect key="frame" x="0.0" y="-1" width="1032" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="UUW-c4-eNA"/>
|
||||
</constraints>
|
||||
|
@ -679,26 +576,26 @@
|
|||
<objects>
|
||||
<tableViewController id="ocL-kj-jxR" customClass="MWMEditorAdditionalNamesTableViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="tQ2-XI-QWd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ListCellIdentifier" textLabel="JcK-nR-UGw" detailTextLabel="Cmi-x5-6Vt" style="IBUITableViewCellStyleSubtitle" id="RXe-xp-xlR" customClass="MWMTableViewCell">
|
||||
<rect key="frame" x="0.0" y="50" width="932" height="44"/>
|
||||
<rect key="frame" x="0.0" y="50" width="1032" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="RXe-xp-xlR" id="g0x-Vt-1FI">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JcK-nR-UGw">
|
||||
<rect key="frame" x="20" y="6" width="31.666666666666668" height="19.333333333333332"/>
|
||||
<rect key="frame" x="20" y="6" width="31.5" height="19.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Cmi-x5-6Vt">
|
||||
<rect key="frame" x="20" y="25.333333333333332" width="30.333333333333332" height="13.333333333333334"/>
|
||||
<rect key="frame" x="20" y="25.5" width="30.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
@ -723,7 +620,7 @@
|
|||
<objects>
|
||||
<tableViewController id="Heu-QR-M0N" customClass="MWMStreetEditorViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="rJJ-UB-6u2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<inset key="scrollIndicatorInsets" minX="0.0" minY="44" maxX="0.0" maxY="0.0"/>
|
||||
|
@ -742,11 +639,11 @@
|
|||
<objects>
|
||||
<viewController id="QlF-CJ-cEG" customClass="MWMObjectsCategorySelectorController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="MIY-NW-Joh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="JbV-y9-HBo">
|
||||
<rect key="frame" x="0.0" y="56" width="932" height="353"/>
|
||||
<rect key="frame" x="0.0" y="80" width="1032" height="1276"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="TableView:PressBackground"/>
|
||||
|
@ -757,7 +654,7 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rI9-RR-sKP" userLabel="Status Bar Background">
|
||||
<rect key="frame" x="0.0" y="-52" width="932" height="108"/>
|
||||
<rect key="frame" x="0.0" y="-28" width="1032" height="108"/>
|
||||
<color key="backgroundColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
|
@ -768,7 +665,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<searchBar contentMode="redraw" translatesAutoresizingMaskIntoConstraints="NO" id="gzF-B7-8pj">
|
||||
<rect key="frame" x="59" y="0.0" width="873" height="56"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="56"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="2uI-k6-ahr"/>
|
||||
|
@ -813,11 +710,11 @@
|
|||
<objects>
|
||||
<viewController id="da4-KT-kzF" customClass="MWMCuisineEditorViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="iTG-qE-svw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" translatesAutoresizingMaskIntoConstraints="NO" id="ina-WD-kps">
|
||||
<rect key="frame" x="0.0" y="56" width="932" height="353"/>
|
||||
<rect key="frame" x="0.0" y="80" width="1032" height="1276"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="TableView:PressBackground"/>
|
||||
|
@ -828,7 +725,7 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HEU-Bu-3wh" userLabel="Status Bar Background">
|
||||
<rect key="frame" x="0.0" y="-52" width="932" height="108"/>
|
||||
<rect key="frame" x="0.0" y="-28" width="1032" height="108"/>
|
||||
<color key="backgroundColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
|
@ -839,7 +736,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<searchBar contentMode="redraw" translatesAutoresizingMaskIntoConstraints="NO" id="z6s-26-dP6">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="56"/>
|
||||
<rect key="frame" x="0.0" y="24" width="1032" height="56"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="44" id="UAk-z1-2EY"/>
|
||||
|
@ -883,11 +780,11 @@
|
|||
<objects>
|
||||
<viewController storyboardIdentifier="DownloadMapsViewController" id="h4a-ne-bSJ" customClass="MWMDownloadMapsViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="XQZ-0V-SyR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="CwW-x8-G3j">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<gestureRecognizers/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
|
@ -899,13 +796,13 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<containerView hidden="YES" opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kXO-Oh-2vO" userLabel="No Maps Container View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<connections>
|
||||
<segue destination="b8o-rZ-x0k" kind="embed" identifier="MapDownloaderNoResultsEmbedViewControllerSegue" id="ish-dC-mkH"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CDj-ol-HRP">
|
||||
<rect key="frame" x="0.0" y="345" width="932" height="85"/>
|
||||
<rect key="frame" x="0.0" y="1292" width="1032" height="84"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="PressBackground"/>
|
||||
|
@ -948,20 +845,20 @@
|
|||
<objects>
|
||||
<viewController storyboardIdentifier="MWMNoMapsViewController" id="3el-Zi-2E4" customClass="MWMNoMapsViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="4WP-vj-Alg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gmw-e3-n53" userLabel="Container" customClass="MWMNoMapsView">
|
||||
<rect key="frame" x="258.33333333333326" y="0.0" width="415.66666666666674" height="409"/>
|
||||
<rect key="frame" x="13" y="24" width="367" height="804"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dCZ-PN-2Ob" userLabel="BoundsView">
|
||||
<rect key="frame" x="16" y="0.0" width="383.66666666666669" height="409"/>
|
||||
<rect key="frame" x="16" y="0.0" width="335" height="804"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="87G-jh-N8H" userLabel="CenteredView">
|
||||
<rect key="frame" x="0.0" y="149.66666666666666" width="383.66666666666669" height="109.66666666666666"/>
|
||||
<rect key="frame" x="0.0" y="347.5" width="335" height="109.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="У вас нет загруженных карт" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="abh-G0-Alr" userLabel="Title">
|
||||
<rect key="frame" x="0.0" y="40" width="383.66666666666669" height="24"/>
|
||||
<rect key="frame" x="0.0" y="40" width="335" height="24"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -971,7 +868,7 @@
|
|||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Загрузите необходимые карты, чтобы находить места и пользоваться навигацией без интернета." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LaW-Ad-mYI" userLabel="Text">
|
||||
<rect key="frame" x="0.0" y="76" width="383.66666666666669" height="33.666666666666657"/>
|
||||
<rect key="frame" x="0.0" y="76" width="335" height="33.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
|
@ -1029,7 +926,7 @@
|
|||
</connections>
|
||||
</view>
|
||||
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Moj-UK-oyl" userLabel="DownloadMaps" customClass="MWMButton">
|
||||
<rect key="frame" x="346" y="325" width="240" height="44"/>
|
||||
<rect key="frame" x="76.5" y="748" width="240" height="44"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="240" id="49x-bx-JJj"/>
|
||||
|
@ -1074,11 +971,11 @@
|
|||
<objects>
|
||||
<viewController storyboardIdentifier="SearchNoResultsViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="0VQ-EO-9Sv" customClass="SearchNoResultsViewController" customModule="Organic_Maps" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="9jm-RW-DZK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="430"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1032" height="1376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EbW-Mp-c6s">
|
||||
<rect key="frame" x="0.0" y="0.0" width="932" height="409"/>
|
||||
<rect key="frame" x="0.0" y="172" width="1032" height="1032"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" secondItem="EbW-Mp-c6s" secondAttribute="height" multiplier="1:1" id="tBC-sb-Q3g"/>
|
||||
|
|
Reference in a new issue