Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
|
|
@ -0,0 +1,10 @@
|
|||
static NSTimeInterval const kMenuViewHideFramesCount = 4.0;
|
||||
|
||||
static inline NSTimeInterval framesDuration(NSTimeInterval const framesCount)
|
||||
{
|
||||
static NSTimeInterval const kFPS = 30.0;
|
||||
static NSTimeInterval const kFrameDuration = 1.0 / kFPS;
|
||||
return kFrameDuration * framesCount;
|
||||
}
|
||||
|
||||
static CGFloat const kViewControlsOffsetToBounds = 6;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
static NSTimeInterval const kMenuViewHideFramesCount = 7.0;
|
||||
static NSTimeInterval const kMenuViewMoveFramesCount = 7.0;
|
||||
|
||||
static inline NSTimeInterval framesDuration(NSTimeInterval const framesCount)
|
||||
{
|
||||
static NSTimeInterval const kFPS = 30.0;
|
||||
static NSTimeInterval const kFrameDuration = 1.0 / kFPS;
|
||||
return kFrameDuration * framesCount;
|
||||
}
|
||||
|
||||
static CGFloat const kViewControlsOffsetToBounds = 4.0;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#import "MWMBottomMenuState.h"
|
||||
#import "MWMMapDownloaderMode.h"
|
||||
#import "MWMNavigationDashboardManager.h"
|
||||
|
||||
@class MapViewController;
|
||||
@class BottomTabBarViewController;
|
||||
@class TrackRecordingButtonViewController;
|
||||
@class SearchQuery;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TrackRecordingButtonState) {
|
||||
TrackRecordingButtonStateHidden,
|
||||
TrackRecordingButtonStateVisible,
|
||||
TrackRecordingButtonStateClosed,
|
||||
};
|
||||
|
||||
@protocol MWMFeatureHolder;
|
||||
|
||||
@interface MWMMapViewControlsManager : NSObject
|
||||
|
||||
+ (MWMMapViewControlsManager *)manager NS_SWIFT_NAME(manager());
|
||||
|
||||
@property(nonatomic) BOOL hidden;
|
||||
@property(nonatomic) BOOL zoomHidden;
|
||||
@property(nonatomic) BOOL sideButtonsHidden;
|
||||
@property(nonatomic) BOOL trafficButtonHidden;
|
||||
@property(nonatomic) MWMBottomMenuState menuState;
|
||||
@property(nonatomic) MWMBottomMenuState menuRestoreState;
|
||||
@property(nonatomic) BOOL isDirectionViewHidden;
|
||||
@property(nonatomic) BottomTabBarViewController * tabBarController;
|
||||
@property(nonatomic) TrackRecordingButtonViewController * trackRecordingButton;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (instancetype)initWithParentController:(MapViewController *)controller;
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle;
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (UIView *)anchorView;
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
|
||||
|
||||
- (void)setTrackRecordingButtonState:(TrackRecordingButtonState)state;
|
||||
|
||||
#pragma mark - MWMNavigationDashboardManager
|
||||
|
||||
- (void)onRoutePrepare;
|
||||
- (void)onRouteRebuild;
|
||||
- (void)onRouteReady:(BOOL)hasWarnings;
|
||||
- (void)onRouteStart;
|
||||
- (void)onRouteStop;
|
||||
|
||||
#pragma mark - MWMSearchManager
|
||||
|
||||
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode;
|
||||
- (BOOL)search:(SearchQuery *)query;
|
||||
- (void)searchOnMap:(SearchQuery *)query;
|
||||
|
||||
#pragma mark - MWMFeatureHolder
|
||||
|
||||
- (id<MWMFeatureHolder>)featureHolder;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,334 @@
|
|||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMAddPlaceNavigationBar.h"
|
||||
#import "MWMMapDownloadDialog.h"
|
||||
#import "MWMMapViewControlsManager+AddPlace.h"
|
||||
#import "MWMNetworkPolicy+UI.h"
|
||||
#import "MWMPlacePageManager.h"
|
||||
#import "MWMPlacePageProtocol.h"
|
||||
#import "MWMSideButtons.h"
|
||||
#import "MWMTrafficButtonViewController.h"
|
||||
#import "MWMMapWidgetsHelper.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
#include <CoreApi/Framework.h>
|
||||
#import <CoreApi/MWMFrameworkHelper.h>
|
||||
|
||||
#include "platform/local_country_file_utils.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "storage/storage_helpers.hpp"
|
||||
|
||||
#include "map/place_page_info.hpp"
|
||||
|
||||
namespace {
|
||||
NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
||||
} // namespace
|
||||
|
||||
@interface MWMMapViewControlsManager () <BottomMenuDelegate>
|
||||
|
||||
@property(nonatomic) MWMSideButtons * sideButtons;
|
||||
@property(nonatomic) MWMTrafficButtonViewController * trafficButton;
|
||||
@property(nonatomic) UIButton * promoButton;
|
||||
@property(nonatomic) UIViewController * menuController;
|
||||
@property(nonatomic) id<MWMPlacePageProtocol> placePageManager;
|
||||
@property(nonatomic) MWMNavigationDashboardManager * navigationManager;
|
||||
@property(nonatomic) SearchOnMapManager * searchManager;
|
||||
|
||||
@property(weak, nonatomic) MapViewController * ownerController;
|
||||
|
||||
@property(nonatomic) BOOL disableStandbyOnRouteFollowing;
|
||||
@property(nonatomic) BOOL isAddingPlace;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMMapViewControlsManager
|
||||
|
||||
+ (MWMMapViewControlsManager *)manager {
|
||||
return [MapViewController sharedController].controlsManager;
|
||||
}
|
||||
|
||||
- (instancetype)initWithParentController:(MapViewController *)controller {
|
||||
if (!controller)
|
||||
return nil;
|
||||
self = [super init];
|
||||
if (!self)
|
||||
return nil;
|
||||
self.ownerController = controller;
|
||||
self.hidden = NO;
|
||||
self.sideButtonsHidden = NO;
|
||||
self.trafficButtonHidden = NO;
|
||||
self.isDirectionViewHidden = YES;
|
||||
self.menuState = MWMBottomMenuStateInactive;
|
||||
self.menuRestoreState = MWMBottomMenuStateInactive;
|
||||
self.isAddingPlace = NO;
|
||||
self.searchManager = controller.searchManager;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden &&
|
||||
self.navigationManager.state != MWMNavigationDashboardStateNavigation;
|
||||
BOOL const isMenuViewUnderStatusBar = self.menuState == MWMBottomMenuStateActive;
|
||||
BOOL const isDirectionViewUnderStatusBar = !self.isDirectionViewHidden;
|
||||
BOOL const isAddPlaceUnderStatusBar =
|
||||
[self.ownerController.view hasSubviewWithViewClass:[MWMAddPlaceNavigationBar class]];
|
||||
BOOL const isNightMode = [UIColor isNightMode];
|
||||
BOOL const isSomethingUnderStatusBar = isNavigationUnderStatusBar ||
|
||||
isDirectionViewUnderStatusBar || isMenuViewUnderStatusBar ||
|
||||
isAddPlaceUnderStatusBar;
|
||||
|
||||
return isSomethingUnderStatusBar || isNightMode ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault;
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (UIView *)anchorView {
|
||||
return self.tabBarController.view;
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[self.trafficButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.trackRecordingButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.tabBarController viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
|
||||
#pragma mark - MWMPlacePageViewManager
|
||||
|
||||
- (void)searchOnMap:(SearchQuery *)query {
|
||||
if (![self search:query])
|
||||
return;
|
||||
|
||||
[self.searchManager startSearchingWithIsRouting:NO];
|
||||
}
|
||||
|
||||
- (BOOL)search:(SearchQuery *)query {
|
||||
if (query.text.length == 0)
|
||||
return NO;
|
||||
|
||||
[self.searchManager startSearchingWithIsRouting:NO];
|
||||
[self.searchManager searchText:query];
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - BottomMenu
|
||||
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode {
|
||||
[self.ownerController openMapsDownloader:mode];
|
||||
}
|
||||
|
||||
- (void)didFinishAddingPlace {
|
||||
self.isAddingPlace = NO;
|
||||
self.trafficButtonHidden = NO;
|
||||
self.menuState = MWMBottomMenuStateInactive;
|
||||
}
|
||||
|
||||
- (void)addPlace {
|
||||
[self addPlace:NO position:nullptr];
|
||||
}
|
||||
|
||||
- (void)addPlace:(BOOL)isBusiness position:(m2::PointD const *)optionalPosition {
|
||||
MapViewController *ownerController = self.ownerController;
|
||||
|
||||
self.isAddingPlace = YES;
|
||||
[self.searchManager close];
|
||||
self.menuState = MWMBottomMenuStateHidden;
|
||||
self.trafficButtonHidden = YES;
|
||||
|
||||
[ownerController dismissPlacePage];
|
||||
|
||||
[MWMAddPlaceNavigationBar showInSuperview:ownerController.view
|
||||
isBusiness:isBusiness
|
||||
position:optionalPosition
|
||||
doneBlock:^{
|
||||
if ([MWMFrameworkHelper canEditMapAtViewportCenter])
|
||||
[ownerController performSegueWithIdentifier:kMapToCategorySelectorSegue sender:nil];
|
||||
else
|
||||
[ownerController.alertController presentIncorrectFeauturePositionAlert];
|
||||
|
||||
[self didFinishAddingPlace];
|
||||
}
|
||||
cancelBlock:^{
|
||||
[self didFinishAddingPlace];
|
||||
}];
|
||||
[ownerController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
#pragma mark - MWMNavigationDashboardManager
|
||||
|
||||
- (void)setDisableStandbyOnRouteFollowing:(BOOL)disableStandbyOnRouteFollowing {
|
||||
if (_disableStandbyOnRouteFollowing == disableStandbyOnRouteFollowing)
|
||||
return;
|
||||
_disableStandbyOnRouteFollowing = disableStandbyOnRouteFollowing;
|
||||
if (disableStandbyOnRouteFollowing)
|
||||
[[MapsAppDelegate theApp] disableStandby];
|
||||
else
|
||||
[[MapsAppDelegate theApp] enableStandby];
|
||||
}
|
||||
|
||||
#pragma mark - Routing
|
||||
|
||||
- (void)onRoutePrepare {
|
||||
auto nm = self.navigationManager;
|
||||
[nm onRoutePrepare];
|
||||
[nm onRoutePointsUpdated];
|
||||
[self.ownerController.bookmarksCoordinator close];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)onRouteRebuild {
|
||||
[self.ownerController.bookmarksCoordinator close];
|
||||
[self.navigationManager onRoutePlanning];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)onRouteReady:(BOOL)hasWarnings {
|
||||
[self.navigationManager onRouteReady:hasWarnings];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)onRouteStart {
|
||||
self.hidden = NO;
|
||||
self.sideButtons.zoomHidden = self.zoomHidden;
|
||||
self.sideButtonsHidden = NO;
|
||||
self.disableStandbyOnRouteFollowing = YES;
|
||||
self.trafficButtonHidden = YES;
|
||||
[self.navigationManager onRouteStart];
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)onRouteStop {
|
||||
self.sideButtons.zoomHidden = self.zoomHidden;
|
||||
[self.navigationManager onRouteStop];
|
||||
self.disableStandbyOnRouteFollowing = NO;
|
||||
self.trafficButtonHidden = NO;
|
||||
self.promoButton.hidden = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MWMSideButtons *)sideButtons {
|
||||
if (!_sideButtons)
|
||||
_sideButtons = [[MWMSideButtons alloc] initWithParentView:self.ownerController.controlsView];
|
||||
return _sideButtons;
|
||||
}
|
||||
|
||||
- (MWMTrafficButtonViewController *)trafficButton {
|
||||
if (!_trafficButton)
|
||||
_trafficButton = [[MWMTrafficButtonViewController alloc] init];
|
||||
return _trafficButton;
|
||||
}
|
||||
|
||||
- (BottomTabBarViewController *)tabBarController {
|
||||
if (!_tabBarController) {
|
||||
MapViewController * ownerController = _ownerController;
|
||||
_tabBarController = [BottomTabBarBuilder buildWithMapViewController:ownerController controlsManager:self];
|
||||
[ownerController addChildViewController:_tabBarController];
|
||||
UIView * tabBarViewSuperView = ownerController.controlsView;
|
||||
[tabBarViewSuperView addSubview:_tabBarController.view];
|
||||
}
|
||||
|
||||
return _tabBarController;
|
||||
}
|
||||
|
||||
- (id<MWMPlacePageProtocol>)placePageManager {
|
||||
if (!_placePageManager)
|
||||
_placePageManager = [[MWMPlacePageManager alloc] init];
|
||||
return _placePageManager;
|
||||
}
|
||||
|
||||
- (MWMNavigationDashboardManager *)navigationManager {
|
||||
if (!_navigationManager)
|
||||
_navigationManager = [[MWMNavigationDashboardManager alloc] initWithParentView:self.ownerController.controlsView];
|
||||
return _navigationManager;
|
||||
}
|
||||
|
||||
@synthesize menuState = _menuState;
|
||||
|
||||
- (void)setHidden:(BOOL)hidden {
|
||||
if (_hidden == hidden)
|
||||
return;
|
||||
// Do not hide the controls view during the place adding process.
|
||||
if (!_isAddingPlace)
|
||||
_hidden = hidden;
|
||||
self.sideButtonsHidden = _sideButtonsHidden;
|
||||
self.trafficButtonHidden = _trafficButtonHidden;
|
||||
self.menuState = hidden ? MWMBottomMenuStateHidden : MWMBottomMenuStateInactive;
|
||||
}
|
||||
|
||||
- (void)setZoomHidden:(BOOL)zoomHidden {
|
||||
_zoomHidden = zoomHidden;
|
||||
self.sideButtons.zoomHidden = zoomHidden;
|
||||
}
|
||||
|
||||
- (void)setSideButtonsHidden:(BOOL)sideButtonsHidden {
|
||||
_sideButtonsHidden = sideButtonsHidden;
|
||||
self.sideButtons.hidden = self.hidden || sideButtonsHidden;
|
||||
}
|
||||
|
||||
- (void)setTrafficButtonHidden:(BOOL)trafficButtonHidden {
|
||||
BOOL const isNavigation = self.navigationManager.state == MWMNavigationDashboardStateNavigation;
|
||||
_trafficButtonHidden = isNavigation || trafficButtonHidden;
|
||||
self.trafficButton.hidden = self.hidden || _trafficButtonHidden;
|
||||
}
|
||||
|
||||
- (void)setTrackRecordingButtonState:(TrackRecordingButtonState)state {
|
||||
if (!_trackRecordingButton) {
|
||||
_trackRecordingButton = [[TrackRecordingButtonViewController alloc] init];
|
||||
}
|
||||
[self.trackRecordingButton setState:state completion:^{
|
||||
[MWMMapWidgetsHelper updateLayoutForAvailableArea];
|
||||
}];
|
||||
if (state == TrackRecordingButtonStateClosed)
|
||||
_trackRecordingButton = nil;
|
||||
}
|
||||
|
||||
- (void)setMenuState:(MWMBottomMenuState)menuState {
|
||||
_menuState = menuState;
|
||||
MapViewController * ownerController = _ownerController;
|
||||
switch (_menuState) {
|
||||
case MWMBottomMenuStateActive:
|
||||
_tabBarController.isHidden = NO;
|
||||
if (_menuController == nil) {
|
||||
_menuController = [BottomMenuBuilder buildMenuWithMapViewController:ownerController
|
||||
controlsManager:self
|
||||
delegate:self];
|
||||
[ownerController presentViewController:_menuController animated:YES completion:nil];
|
||||
}
|
||||
break;
|
||||
case MWMBottomMenuStateLayers:
|
||||
_tabBarController.isHidden = NO;
|
||||
if (_menuController == nil) {
|
||||
_menuController = [BottomMenuBuilder buildLayersWithMapViewController:ownerController
|
||||
controlsManager:self
|
||||
delegate:self];
|
||||
[ownerController presentViewController:_menuController animated:YES completion:nil];
|
||||
}
|
||||
break;
|
||||
case MWMBottomMenuStateInactive:
|
||||
_tabBarController.isHidden = NO;
|
||||
if (_menuController != nil) {
|
||||
[_menuController dismissViewControllerAnimated:YES completion:nil];
|
||||
_menuController = nil;
|
||||
}
|
||||
break;
|
||||
case MWMBottomMenuStateHidden:
|
||||
_tabBarController.isHidden = YES;
|
||||
if (_menuController != nil) {
|
||||
[_menuController dismissViewControllerAnimated:YES completion:nil];
|
||||
_menuController = nil;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - MWMFeatureHolder
|
||||
|
||||
- (id<MWMFeatureHolder>)featureHolder {
|
||||
return self.placePageManager;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#import "MWMMyPositionMode.h"
|
||||
|
||||
@interface MWMSideButtons : NSObject
|
||||
|
||||
+ (MWMSideButtons *)buttons;
|
||||
|
||||
@property (nonatomic) BOOL zoomHidden;
|
||||
@property (nonatomic) BOOL hidden;
|
||||
@property (nonatomic, readonly) UIView *view;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (instancetype)initWithParentView:(UIView *)view;
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(MWMMyPositionMode)mode;
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
#import "MWMSideButtons.h"
|
||||
#import "MWMButton.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMRouter.h"
|
||||
#import "MWMSettings.h"
|
||||
#import "MWMSideButtonsView.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
||||
#include <CoreApi/Framework.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
NSString * const kMWMSideButtonsViewNibName = @"MWMSideButtonsView";
|
||||
NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapToShowSideButtonsToast";
|
||||
} // namespace
|
||||
|
||||
@interface MWMMapViewControlsManager ()
|
||||
|
||||
@property(nonatomic) MWMSideButtons * sideButtons;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMSideButtons ()
|
||||
|
||||
@property(nonatomic) IBOutlet MWMSideButtonsView * sideView;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton * zoomInButton;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton * zoomOutButton;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton * locationButton;
|
||||
|
||||
@property(nonatomic) BOOL zoomSwipeEnabled;
|
||||
@property(nonatomic, readonly) BOOL isZoomEnabled;
|
||||
|
||||
@property(nonatomic) MWMMyPositionMode locationMode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSideButtons
|
||||
|
||||
- (UIView *)view {
|
||||
return self.sideView;
|
||||
}
|
||||
|
||||
+ (MWMSideButtons *)buttons { return [MWMMapViewControlsManager manager].sideButtons; }
|
||||
- (instancetype)initWithParentView:(UIView *)view
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[NSBundle.mainBundle loadNibNamed:kMWMSideButtonsViewNibName owner:self options:nil];
|
||||
[view addSubview:self.sideView];
|
||||
[self.sideView setNeedsLayout];
|
||||
self.zoomSwipeEnabled = NO;
|
||||
self.zoomHidden = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame { [[self buttons].sideView updateAvailableArea:frame]; }
|
||||
|
||||
- (void)zoomIn
|
||||
{
|
||||
GetFramework().Scale(Framework::SCALE_MAG, true);
|
||||
}
|
||||
|
||||
- (void)zoomOut
|
||||
{
|
||||
GetFramework().Scale(Framework::SCALE_MIN, true);
|
||||
}
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(MWMMyPositionMode)mode
|
||||
{
|
||||
[self refreshLocationButtonState:mode];
|
||||
self.locationMode = mode;
|
||||
}
|
||||
|
||||
#pragma mark - Location button
|
||||
|
||||
- (void)refreshLocationButtonState:(MWMMyPositionMode)state
|
||||
{
|
||||
MWMButton * locBtn = self.locationButton;
|
||||
[locBtn.imageView stopRotation];
|
||||
switch (state)
|
||||
{
|
||||
case MWMMyPositionModePendingPosition:
|
||||
{
|
||||
[locBtn setStyleNameAndApply: @"ButtonPending"];
|
||||
[locBtn.imageView startRotation:1];
|
||||
break;
|
||||
}
|
||||
case MWMMyPositionModeNotFollow:
|
||||
case MWMMyPositionModeNotFollowNoPosition: [locBtn setStyleNameAndApply: @"ButtonGetPosition"]; break;
|
||||
case MWMMyPositionModeFollow: [locBtn setStyleNameAndApply: @"ButtonFollow"]; break;
|
||||
case MWMMyPositionModeFollowAndRotate: [locBtn setStyleNameAndApply: @"ButtonFollowAndRotate"]; break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)zoomTouchDown:(UIButton *)sender { self.zoomSwipeEnabled = YES; }
|
||||
- (IBAction)zoomTouchUpInside:(UIButton *)sender
|
||||
{
|
||||
self.zoomSwipeEnabled = NO;
|
||||
if ([sender isEqual:self.zoomInButton])
|
||||
[self zoomIn];
|
||||
else
|
||||
[self zoomOut];
|
||||
}
|
||||
|
||||
- (IBAction)zoomTouchUpOutside:(UIButton *)sender { self.zoomSwipeEnabled = NO; }
|
||||
- (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender
|
||||
{
|
||||
if (!self.zoomSwipeEnabled)
|
||||
return;
|
||||
UIView * const superview = self.sideView.superview;
|
||||
CGFloat const translation =
|
||||
-[sender translationInView:superview].y / superview.bounds.size.height;
|
||||
|
||||
CGFloat const scaleFactor = exp(translation);
|
||||
GetFramework().Scale(scaleFactor, false);
|
||||
}
|
||||
|
||||
- (IBAction)locationTouchUpInside
|
||||
{
|
||||
[MWMLocationManager enableLocationAlert];
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (BOOL)zoomHidden { return self.sideView.zoomHidden; }
|
||||
- (void)setZoomHidden:(BOOL)zoomHidden
|
||||
{
|
||||
if ([MWMRouter isRoutingActive])
|
||||
self.sideView.zoomHidden = NO;
|
||||
else
|
||||
self.sideView.zoomHidden = [MWMSettings zoomButtonsEnabled] ? zoomHidden : YES;
|
||||
}
|
||||
|
||||
- (BOOL)hidden { return self.sideView.hidden; }
|
||||
- (void)setHidden:(BOOL)hidden
|
||||
{
|
||||
if (!self.hidden && hidden)
|
||||
[Toast showWithText:L(@"long_tap_toast")];
|
||||
|
||||
return [self.sideView setHidden:hidden animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
@interface MWMSideButtonsView : UIView
|
||||
|
||||
@property (nonatomic) BOOL zoomHidden;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("initWithFrame is not available")));
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
|
||||
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated;
|
||||
|
||||
- (void)updateAvailableArea:(CGRect)frame;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
#import "MWMSideButtonsView.h"
|
||||
#import "MWMButton.h"
|
||||
#import "MWMRouter.h"
|
||||
#import "MWMMapViewControlsCommon.h"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
namespace {
|
||||
CGFloat const kLocationButtonSpacingMax = 52;
|
||||
CGFloat const kLocationButtonSpacingMin = 8;
|
||||
CGFloat const kButtonsTopOffset = 6;
|
||||
CGFloat const kButtonsBottomOffset = 6;
|
||||
} // namespace
|
||||
|
||||
@interface MWMSideButtonsView ()
|
||||
|
||||
@property(weak, nonatomic) IBOutlet MWMButton *zoomIn;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton *zoomOut;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton *location;
|
||||
|
||||
@property(nonatomic) CGRect availableArea;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMSideButtonsView
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
CGFloat spacing = self.availableHeight - self.zoomOut.maxY - self.location.height;
|
||||
spacing = math::Clamp(spacing, kLocationButtonSpacingMin, kLocationButtonSpacingMax);
|
||||
|
||||
if (!IPAD && (UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeLeft || UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeRight) && [MWMRouter isRoutingActive]) {
|
||||
spacing = spacing - 36;
|
||||
}
|
||||
|
||||
self.location.minY = self.zoomOut.maxY + spacing;
|
||||
self.bounds = {{}, {self.zoomOut.width, self.location.maxY}};
|
||||
if (self.zoomHidden)
|
||||
self.height = self.location.height;
|
||||
self.location.maxY = self.height;
|
||||
|
||||
[self animate];
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)layoutXPosition:(BOOL)hidden {
|
||||
if (UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
|
||||
if (hidden)
|
||||
self.maxX = 0;
|
||||
else
|
||||
self.minX = self.availableArea.origin.x + kViewControlsOffsetToBounds;
|
||||
} else {
|
||||
const auto availableAreaMaxX = self.availableArea.origin.x + self.availableArea.size.width;
|
||||
if (hidden)
|
||||
self.minX = self.superview.width;
|
||||
else
|
||||
self.maxX = availableAreaMaxX - kViewControlsOffsetToBounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutYPosition {
|
||||
CGFloat const centerShift = (self.height - self.zoomIn.midY - self.zoomOut.midY) / 2;
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.midY = centerShift + self.superview.height / 2;
|
||||
if ([MWMRouter isRoutingActive]) {
|
||||
self.midY = self.midY - 18;
|
||||
}
|
||||
if (self.maxY > self.bottomBound)
|
||||
self.maxY = self.bottomBound;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fadeZoomButtonsShow:(BOOL)show {
|
||||
CGFloat const alpha = show ? 1.0 : 0.0;
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.zoomIn.alpha = alpha;
|
||||
self.zoomOut.alpha = alpha;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fadeLocationButtonShow:(BOOL)show {
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.location.alpha = show ? 1.0 : 0.0;
|
||||
}];
|
||||
}
|
||||
|
||||
// Show/hide zoom and location buttons depending on available vertical space.
|
||||
- (void)animate {
|
||||
[self layoutYPosition];
|
||||
|
||||
BOOL const isZoomHidden = self.zoomIn.alpha == 0.0;
|
||||
BOOL const willZoomHide = (self.location.maxY > self.availableHeight);
|
||||
if (willZoomHide != isZoomHidden)
|
||||
[self fadeZoomButtonsShow: !willZoomHide];
|
||||
|
||||
BOOL const isLocationHidden = self.location.alpha == 0.0;
|
||||
BOOL const willLocationHide = (self.location.height > self.availableHeight);
|
||||
if (willLocationHide != isLocationHidden)
|
||||
[self fadeLocationButtonShow: !willLocationHide];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setZoomHidden:(BOOL)zoomHidden {
|
||||
_zoomHidden = zoomHidden;
|
||||
self.zoomIn.hidden = zoomHidden;
|
||||
self.zoomOut.hidden = zoomHidden;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated {
|
||||
if (animated) {
|
||||
if (self.hidden == hidden)
|
||||
return;
|
||||
// Side buttons should be visible during any our show/hide anamation.
|
||||
// Visibility should be detemined by alpha, not self.hidden.
|
||||
self.hidden = NO;
|
||||
[UIView animateWithDuration:kDefaultAnimationDuration
|
||||
animations:^{
|
||||
self.alpha = hidden ? 0.0 : 1.0;
|
||||
[self layoutXPosition:hidden];
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
self.hidden = hidden;
|
||||
}];
|
||||
} else {
|
||||
self.hidden = hidden;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateAvailableArea:(CGRect)frame {
|
||||
if (CGRectEqualToRect(self.availableArea, frame))
|
||||
return;
|
||||
// If during our show/hide animation position is changed it is corrupted.
|
||||
// Such kind of animation has 2 keys (opacity and position).
|
||||
// But there are other animation cases like change of orientation.
|
||||
// So we can use condition below:
|
||||
// if (self.layer.animationKeys.count != 2)
|
||||
// More elegant way is to check if x values are changed.
|
||||
// If no - there is no need to update self x values.
|
||||
if (self.availableArea.origin.x != frame.origin.x || self.availableArea.size.width != frame.size.width)
|
||||
{
|
||||
self.availableArea = frame;
|
||||
[self layoutXPosition:self.hidden];
|
||||
}
|
||||
else
|
||||
self.availableArea = frame;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (CGFloat)availableHeight {
|
||||
return self.availableArea.size.height - kButtonsTopOffset - kButtonsBottomOffset;
|
||||
}
|
||||
|
||||
- (CGFloat)topBound {
|
||||
return self.availableArea.origin.y + kButtonsTopOffset;
|
||||
}
|
||||
- (CGFloat)bottomBound {
|
||||
auto const area = self.availableArea;
|
||||
return area.origin.y + area.size.height - kButtonsBottomOffset;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" 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="15704"/>
|
||||
<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="MWMSideButtons">
|
||||
<connections>
|
||||
<outlet property="locationButton" destination="fUK-2V-4ya" id="CBK-kp-DFE"/>
|
||||
<outlet property="sideView" destination="ek2-ZW-pCm" id="sbV-Vv-Wrp"/>
|
||||
<outlet property="zoomInButton" destination="NO3-Xl-Oka" id="ePH-BR-gfW"/>
|
||||
<outlet property="zoomOutButton" destination="hwn-8L-cFX" id="fYk-mf-gUY"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<view contentMode="scaleToFill" id="ek2-ZW-pCm" customClass="MWMSideButtonsView" propertyAccessControl="none">
|
||||
<rect key="frame" x="0.0" y="0.0" width="56" height="228"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NO3-Xl-Oka" userLabel="ZoomIn" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="56" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_zoom_in_light">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="ButtonZoomIn"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="5VF-m8-Lwc"/>
|
||||
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="wbL-zf-fH8"/>
|
||||
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="w6V-A2-cZM"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hwn-8L-cFX" userLabel="ZoomOut" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="64" width="56" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_zoom_out_light">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="ButtonZoomOut"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="o4X-Kp-9ka"/>
|
||||
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="Gcq-hm-Nk8"/>
|
||||
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="cX7-sp-3L3"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-2V-4ya" userLabel="Location" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="172" width="56" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_get_position_light">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="locationTouchUpInside" destination="-1" eventType="touchUpInside" id="CMC-xb-Dpk"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<gestureRecognizers/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<viewLayoutGuide key="safeArea" id="rMs-pl-xhs"/>
|
||||
<connections>
|
||||
<outlet property="location" destination="fUK-2V-4ya" id="lgn-MB-VVy"/>
|
||||
<outlet property="zoomIn" destination="NO3-Xl-Oka" id="1sc-ei-oRj"/>
|
||||
<outlet property="zoomOut" destination="hwn-8L-cFX" id="htY-bc-Ugh"/>
|
||||
<outletCollection property="gestureRecognizers" destination="6qU-Ff-Ae5" appends="YES" id="jeT-Jr-P7T"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="165" y="-6"/>
|
||||
</view>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<panGestureRecognizer minimumNumberOfTouches="1" id="6qU-Ff-Ae5">
|
||||
<connections>
|
||||
<action selector="zoomSwipe:" destination="-1" id="jq1-Qs-vUJ"/>
|
||||
</connections>
|
||||
</panGestureRecognizer>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="btn_get_position_light" width="56" height="56"/>
|
||||
<image name="btn_zoom_in_light" width="56" height="56"/>
|
||||
<image name="btn_zoom_out_light" width="56" height="56"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
@class MWMZoomButtonsView;
|
||||
|
||||
@interface MWMZoomButtons : NSObject
|
||||
|
||||
@property (nonatomic) BOOL hidden;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (instancetype)initWithParentView:(UIView *)view;
|
||||
- (void)setTopBound:(CGFloat)bound;
|
||||
- (void)setBottomBound:(CGFloat)bound;
|
||||
- (void)mwm_refreshUI;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
#import "MWMZoomButtons.h"
|
||||
#import "MWMZoomButtonsView.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
|
||||
#include "Framework.h"
|
||||
#include "platform/settings.hpp"
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
static NSString * const kMWMZoomButtonsViewNibName = @"MWMZoomButtonsView";
|
||||
|
||||
|
||||
@interface MWMZoomButtons()
|
||||
|
||||
@property (nonatomic) IBOutlet MWMZoomButtonsView * zoomView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton * zoomInButton;
|
||||
@property (weak, nonatomic) IBOutlet UIButton * zoomOutButton;
|
||||
|
||||
@property (nonatomic) BOOL zoomSwipeEnabled;
|
||||
@property (nonatomic, readonly) BOOL isZoomEnabled;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMZoomButtons
|
||||
|
||||
- (instancetype)initWithParentView:(UIView *)view
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:kMWMZoomButtonsViewNibName owner:self options:nil];
|
||||
[view addSubview:self.zoomView];
|
||||
[self.zoomView layoutIfNeeded];
|
||||
self.zoomView.topBound = 0.0;
|
||||
self.zoomView.bottomBound = view.height;
|
||||
self.zoomSwipeEnabled = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTopBound:(CGFloat)bound
|
||||
{
|
||||
self.zoomView.topBound = bound;
|
||||
}
|
||||
|
||||
- (void)setBottomBound:(CGFloat)bound
|
||||
{
|
||||
self.zoomView.bottomBound = bound;
|
||||
}
|
||||
|
||||
- (void)zoomIn
|
||||
{
|
||||
[Statistics logEvent:kStatEventName(kStatZoom, kStatIn)];
|
||||
GetFramework().Scale(Framework::SCALE_MAG, true);
|
||||
}
|
||||
|
||||
- (void)zoomOut
|
||||
{
|
||||
[Statistics logEvent:kStatEventName(kStatZoom, kStatOut)];
|
||||
GetFramework().Scale(Framework::SCALE_MIN, true);
|
||||
}
|
||||
|
||||
- (void)mwm_refreshUI
|
||||
{
|
||||
[self.zoomView mwm_refreshUI];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (IBAction)zoomTouchDown:(UIButton *)sender
|
||||
{
|
||||
self.zoomSwipeEnabled = YES;
|
||||
}
|
||||
|
||||
- (IBAction)zoomTouchUpInside:(UIButton *)sender
|
||||
{
|
||||
self.zoomSwipeEnabled = NO;
|
||||
if ([sender isEqual:self.zoomInButton])
|
||||
[self zoomIn];
|
||||
else
|
||||
[self zoomOut];
|
||||
}
|
||||
|
||||
- (IBAction)zoomTouchUpOutside:(UIButton *)sender
|
||||
{
|
||||
self.zoomSwipeEnabled = NO;
|
||||
}
|
||||
|
||||
- (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender
|
||||
{
|
||||
if (!self.zoomSwipeEnabled)
|
||||
return;
|
||||
UIView * const superview = self.zoomView.superview;
|
||||
CGFloat const translation = -[sender translationInView:superview].y / superview.bounds.size.height;
|
||||
|
||||
CGFloat const scaleFactor = exp(translation);
|
||||
GetFramework().Scale(scaleFactor, false);
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (BOOL)isZoomEnabled
|
||||
{
|
||||
bool zoomButtonsEnabled = true;
|
||||
(void)settings::Get("ZoomButtonsEnabled", zoomButtonsEnabled);
|
||||
return zoomButtonsEnabled;
|
||||
}
|
||||
|
||||
- (BOOL)hidden
|
||||
{
|
||||
return self.isZoomEnabled ? self.zoomView.hidden : YES;
|
||||
}
|
||||
|
||||
- (void)setHidden:(BOOL)hidden
|
||||
{
|
||||
if (self.isZoomEnabled)
|
||||
[self.zoomView setHidden:hidden animated:YES];
|
||||
else
|
||||
self.zoomView.hidden = YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface MWMZoomButtonsView : UIView
|
||||
|
||||
@property (nonatomic) CGFloat topBound;
|
||||
@property (nonatomic) CGFloat bottomBound;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("initWithFrame is not available")));
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
|
||||
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#import "Common.h"
|
||||
#import "MWMZoomButtonsView.h"
|
||||
#import "MWMMapViewControlsCommon.h"
|
||||
|
||||
static CGFloat const kZoomViewOffsetToTopBound = 12.0;
|
||||
static CGFloat const kZoomViewOffsetToBottomBound = 40.0;
|
||||
static CGFloat const kZoomViewOffsetToFrameBound = 294.0;
|
||||
static CGFloat const kZoomViewHideBoundPercent = 0.4;
|
||||
|
||||
@interface MWMZoomButtonsView()
|
||||
|
||||
@property (nonatomic) CGRect defaultBounds;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMZoomButtonsView
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
self.defaultBounds = self.bounds;
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
self.bounds = self.defaultBounds;
|
||||
[self layoutXPosition:self.hidden];
|
||||
[self layoutYPosition];
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)layoutXPosition:(BOOL)hidden
|
||||
{
|
||||
if (hidden)
|
||||
self.minX = self.superview.width;
|
||||
else
|
||||
self.maxX = self.superview.width - kViewControlsOffsetToBounds;
|
||||
}
|
||||
|
||||
- (void)layoutYPosition
|
||||
{
|
||||
CGFloat const maxY = MIN(self.superview.height - kZoomViewOffsetToFrameBound, self.bottomBound - kZoomViewOffsetToBottomBound);
|
||||
self.minY = MAX(maxY - self.height, self.topBound + kZoomViewOffsetToTopBound);
|
||||
}
|
||||
|
||||
- (void)moveAnimated
|
||||
{
|
||||
if (self.hidden)
|
||||
return;
|
||||
[UIView animateWithDuration:framesDuration(kMenuViewMoveFramesCount) animations:^{ [self layoutYPosition]; }];
|
||||
}
|
||||
|
||||
- (void)fadeAnimatedIn:(BOOL)show
|
||||
{
|
||||
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^{ self.alpha = show ? 1.0 : 0.0; }];
|
||||
}
|
||||
|
||||
- (void)animate
|
||||
{
|
||||
CGFloat const hideBound = kZoomViewHideBoundPercent * self.superview.height;
|
||||
BOOL const isHidden = self.alpha == 0.0;
|
||||
BOOL const willHide = (self.bottomBound < hideBound) || (self.defaultBounds.size.height > self.bottomBound - self.topBound);
|
||||
if (willHide)
|
||||
{
|
||||
if (!isHidden)
|
||||
[self fadeAnimatedIn:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self moveAnimated];
|
||||
if (isHidden)
|
||||
[self fadeAnimatedIn:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated
|
||||
{
|
||||
if (animated)
|
||||
{
|
||||
if (self.hidden == hidden)
|
||||
return;
|
||||
if (!hidden)
|
||||
self.hidden = NO;
|
||||
[self layoutXPosition:!hidden];
|
||||
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^
|
||||
{
|
||||
[self layoutXPosition:hidden];
|
||||
}
|
||||
completion:^(BOOL finished)
|
||||
{
|
||||
if (hidden)
|
||||
self.hidden = YES;
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.hidden = hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@synthesize topBound = _topBound;
|
||||
|
||||
- (void)setTopBound:(CGFloat)topBound
|
||||
{
|
||||
if (equalScreenDimensions(_topBound, topBound))
|
||||
return;
|
||||
_topBound = topBound;
|
||||
[self animate];
|
||||
}
|
||||
|
||||
- (CGFloat)topBound
|
||||
{
|
||||
return MAX(0.0, _topBound);
|
||||
}
|
||||
|
||||
@synthesize bottomBound = _bottomBound;
|
||||
|
||||
- (void)setBottomBound:(CGFloat)bottomBound
|
||||
{
|
||||
if (equalScreenDimensions(_bottomBound, bottomBound))
|
||||
return;
|
||||
_bottomBound = bottomBound;
|
||||
[self animate];
|
||||
}
|
||||
|
||||
- (CGFloat)bottomBound
|
||||
{
|
||||
if (!self.superview)
|
||||
return _bottomBound;
|
||||
BOOL const isPortrait = self.superview.width < self.superview.height;
|
||||
CGFloat limit = IPAD ? 320.0 : isPortrait ? 200.0 : 80.0;
|
||||
return MIN(self.superview.height - limit, _bottomBound);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMZoomButtons">
|
||||
<connections>
|
||||
<outlet property="zoomInButton" destination="NO3-Xl-Oka" id="ePH-BR-gfW"/>
|
||||
<outlet property="zoomOutButton" destination="hwn-8L-cFX" id="fYk-mf-gUY"/>
|
||||
<outlet property="zoomView" destination="ek2-ZW-pCm" id="N0e-Rh-Unp"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<view contentMode="scaleToFill" id="ek2-ZW-pCm" customClass="MWMZoomButtonsView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="56" height="116"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="NO3-Xl-Oka" userLabel="ZoomIn" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="56" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_zoom_in_light">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="imageName" value="btn_zoom_in"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="5VF-m8-Lwc"/>
|
||||
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="wbL-zf-fH8"/>
|
||||
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="w6V-A2-cZM"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="hwn-8L-cFX" userLabel="ZoomOut" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="60" width="56" height="56"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" image="btn_zoom_out_light">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="imageName" value="btn_zoom_out"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="o4X-Kp-9ka"/>
|
||||
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="Gcq-hm-Nk8"/>
|
||||
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="cX7-sp-3L3"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<gestureRecognizers/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="6qU-Ff-Ae5" appends="YES" id="jeT-Jr-P7T"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="165" y="-6"/>
|
||||
</view>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<panGestureRecognizer minimumNumberOfTouches="1" id="6qU-Ff-Ae5">
|
||||
<connections>
|
||||
<action selector="zoomSwipe:" destination="-1" id="jq1-Qs-vUJ"/>
|
||||
</connections>
|
||||
</panGestureRecognizer>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="btn_zoom_in_light" width="56" height="56"/>
|
||||
<image name="btn_zoom_out_light" width="56" height="56"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
final class TrackRecordingButtonViewController: MWMViewController {
|
||||
|
||||
private enum Constants {
|
||||
static let buttonDiameter = CGFloat(48)
|
||||
static let topOffset = CGFloat(6)
|
||||
static let trailingOffset = CGFloat(10)
|
||||
static let blinkingDuration = 1.0
|
||||
static let color: (lighter: UIColor, darker: UIColor) = (.red, .red.darker(percent: 0.3))
|
||||
}
|
||||
|
||||
private let trackRecordingManager: TrackRecordingManager = .shared
|
||||
private let button = BottomTabBarButton()
|
||||
private var blinkingTimer: Timer?
|
||||
private var topConstraint = NSLayoutConstraint()
|
||||
private var trailingConstraint = NSLayoutConstraint()
|
||||
private var state: TrackRecordingButtonState = .hidden
|
||||
|
||||
private static var availableArea: CGRect = .zero
|
||||
private static var topConstraintValue: CGFloat {
|
||||
availableArea.origin.y + Constants.topOffset
|
||||
}
|
||||
private static var trailingConstraintValue: CGFloat {
|
||||
-(UIScreen.main.bounds.maxX - availableArea.maxX + Constants.trailingOffset)
|
||||
}
|
||||
|
||||
@objc
|
||||
init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
let ownerViewController = MapViewController.shared()
|
||||
ownerViewController?.addChild(self)
|
||||
ownerViewController?.controlsView.addSubview(view)
|
||||
self.setupView()
|
||||
self.layout()
|
||||
self.startTimer()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setState(self.state, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
@objc
|
||||
func setState(_ state: TrackRecordingButtonState, completion: (() -> Void)?) {
|
||||
self.state = state
|
||||
switch state {
|
||||
case .visible:
|
||||
setHidden(false, completion: nil)
|
||||
case .hidden:
|
||||
setHidden(true, completion: completion)
|
||||
case .closed:
|
||||
close(completion: completion)
|
||||
@unknown default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func setupView() {
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(button)
|
||||
|
||||
button.setStyleAndApply(.trackRecordingWidgetButton)
|
||||
button.tintColor = Constants.color.darker
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.setImage(UIImage(resource: .icMenuBookmarkTrackRecording), for: .normal)
|
||||
button.addTarget(self, action: #selector(didTap), for: .touchUpInside)
|
||||
button.isHidden = true
|
||||
}
|
||||
|
||||
private func layout() {
|
||||
guard let superview = view.superview else { return }
|
||||
topConstraint = view.topAnchor.constraint(equalTo: superview.topAnchor, constant: Self.topConstraintValue)
|
||||
trailingConstraint = view.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: Self.trailingConstraintValue)
|
||||
NSLayoutConstraint.activate([
|
||||
topConstraint,
|
||||
trailingConstraint,
|
||||
view.widthAnchor.constraint(equalToConstant: Constants.buttonDiameter),
|
||||
view.heightAnchor.constraint(equalToConstant: Constants.buttonDiameter),
|
||||
|
||||
button.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
button.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
button.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
guard let superview = view.superview else { return }
|
||||
superview.animateConstraints {
|
||||
self.topConstraint.constant = Self.topConstraintValue
|
||||
self.trailingConstraint.constant = Self.trailingConstraintValue
|
||||
}
|
||||
}
|
||||
|
||||
private func startTimer() {
|
||||
guard blinkingTimer == nil else { return }
|
||||
var lighter = false
|
||||
let timer = Timer.scheduledTimer(withTimeInterval: Constants.blinkingDuration, repeats: true) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
UIView.animate(withDuration: Constants.blinkingDuration, animations: {
|
||||
self.button.tintColor = lighter ? Constants.color.lighter : Constants.color.darker
|
||||
lighter.toggle()
|
||||
})
|
||||
}
|
||||
blinkingTimer = timer
|
||||
RunLoop.current.add(timer, forMode: .common)
|
||||
}
|
||||
|
||||
private func stopTimer() {
|
||||
blinkingTimer?.invalidate()
|
||||
blinkingTimer = nil
|
||||
}
|
||||
|
||||
private func setHidden(_ hidden: Bool, completion: (() -> Void)?) {
|
||||
UIView.transition(with: self.view,
|
||||
duration: kDefaultAnimationDuration,
|
||||
options: .transitionCrossDissolve,
|
||||
animations: {
|
||||
self.button.isHidden = hidden
|
||||
}) { _ in
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
private func close(completion: (() -> Void)?) {
|
||||
stopTimer()
|
||||
setHidden(true) { [weak self] in
|
||||
guard let self else { return }
|
||||
self.removeFromParent()
|
||||
self.view.removeFromSuperview()
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
static func updateAvailableArea(_ frame: CGRect) {
|
||||
availableArea = frame
|
||||
guard let button = MapViewController.shared()?.controlsManager.trackRecordingButton else { return }
|
||||
DispatchQueue.main.async {
|
||||
button.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc
|
||||
private func didTap(_ sender: Any) {
|
||||
MapViewController.shared()?.showTrackRecordingPlacePage()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#import "MWMViewController.h"
|
||||
|
||||
@interface MWMTrafficButtonViewController : MWMViewController
|
||||
|
||||
+ (MWMTrafficButtonViewController *)controller;
|
||||
|
||||
@property(nonatomic) BOOL hidden;
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
#import "MWMTrafficButtonViewController.h"
|
||||
|
||||
#import <CoreApi/MWMMapOverlayManager.h>
|
||||
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMButton.h"
|
||||
#import "MWMMapViewControlsCommon.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MapViewController.h"
|
||||
#import "SwiftBridge.h"
|
||||
#import "base/assert.hpp"
|
||||
|
||||
namespace {
|
||||
CGFloat const kTopOffset = 6;
|
||||
|
||||
NSArray<UIImage *> *imagesWithName(NSString *name) {
|
||||
NSUInteger const imagesCount = 3;
|
||||
NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:imagesCount];
|
||||
NSString *mode = [UIColor isNightMode] ? @"dark" : @"light";
|
||||
for (NSUInteger i = 1; i <= imagesCount; i += 1) {
|
||||
NSString *imageName = [NSString stringWithFormat:@"%@_%@_%@", name, mode, @(i).stringValue];
|
||||
[images addObject:static_cast<UIImage *_Nonnull>([UIImage imageNamed:imageName])];
|
||||
}
|
||||
return [images copy];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@interface MWMMapViewControlsManager ()
|
||||
|
||||
@property(nonatomic) MWMTrafficButtonViewController *trafficButton;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMTrafficButtonViewController () <MWMMapOverlayManagerObserver, ThemeListener>
|
||||
|
||||
@property(nonatomic) NSLayoutConstraint *topOffset;
|
||||
@property(nonatomic) NSLayoutConstraint *leftOffset;
|
||||
@property(nonatomic) CGRect availableArea;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMTrafficButtonViewController
|
||||
|
||||
+ (MWMTrafficButtonViewController *)controller {
|
||||
return [MWMMapViewControlsManager manager].trafficButton;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
MapViewController *ovc = [MapViewController sharedController];
|
||||
[ovc addChildViewController:self];
|
||||
[ovc.controlsView addSubview:self.view];
|
||||
[self configLayout];
|
||||
[self applyTheme];
|
||||
[StyleManager.shared addListener:self];
|
||||
[MWMMapOverlayManager addObserver:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[StyleManager.shared removeListener:self];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
[Toast hideAll];
|
||||
}
|
||||
|
||||
- (void)configLayout {
|
||||
UIView *sv = self.view;
|
||||
UIView *ov = sv.superview;
|
||||
|
||||
self.topOffset = [sv.topAnchor constraintEqualToAnchor:ov.topAnchor constant:kTopOffset];
|
||||
self.topOffset.active = YES;
|
||||
self.leftOffset = [sv.leadingAnchor constraintEqualToAnchor:ov.leadingAnchor constant:kViewControlsOffsetToBounds];
|
||||
self.leftOffset.active = YES;
|
||||
}
|
||||
|
||||
- (void)setHidden:(BOOL)hidden {
|
||||
_hidden = hidden;
|
||||
[self refreshLayout];
|
||||
}
|
||||
|
||||
- (void)refreshLayout {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
auto const availableArea = self.availableArea;
|
||||
auto const fitInAvailableArea = CGRectGetMaxY(self.view.frame) < CGRectGetMaxY(availableArea) + kTopOffset;
|
||||
auto const shouldHide = self.hidden || !fitInAvailableArea;
|
||||
auto const leftOffset = shouldHide ? -self.view.width : availableArea.origin.x + kViewControlsOffsetToBounds;
|
||||
self.topOffset.constant = availableArea.origin.y + kTopOffset;
|
||||
self.leftOffset.constant = leftOffset;
|
||||
self.view.alpha = shouldHide ? 0 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)handleTrafficState:(MWMMapOverlayTrafficState)state {
|
||||
MWMButton *btn = (MWMButton *)self.view;
|
||||
UIImageView *iv = btn.imageView;
|
||||
switch (state) {
|
||||
case MWMMapOverlayTrafficStateDisabled:
|
||||
CHECK(false, ("Incorrect traffic manager state."));
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateEnabled:
|
||||
btn.imageName = @"btn_traffic_on";
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateWaitingData:
|
||||
iv.animationImages = imagesWithName(@"btn_traffic_update");
|
||||
iv.animationDuration = 0.8;
|
||||
[iv startAnimating];
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateOutdated:
|
||||
btn.imageName = @"btn_traffic_outdated";
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateNoData:
|
||||
btn.imageName = @"btn_traffic_on";
|
||||
[Toast showWithText:L(@"traffic_data_unavailable")];
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateNetworkError:
|
||||
[MWMMapOverlayManager setTrafficEnabled:NO];
|
||||
[[MWMAlertViewController activeAlertController] presentNoConnectionAlert];
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateExpiredData:
|
||||
btn.imageName = @"btn_traffic_outdated";
|
||||
[Toast showWithText:L(@"traffic_update_maps_text")];
|
||||
break;
|
||||
case MWMMapOverlayTrafficStateExpiredApp:
|
||||
btn.imageName = @"btn_traffic_outdated";
|
||||
[Toast showWithText:L(@"traffic_update_app_message")];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleIsolinesState:(MWMMapOverlayIsolinesState)state {
|
||||
switch (state) {
|
||||
case MWMMapOverlayIsolinesStateDisabled:
|
||||
break;
|
||||
case MWMMapOverlayIsolinesStateEnabled:
|
||||
if (![MWMMapOverlayManager isolinesVisible])
|
||||
[Toast showWithText:L(@"isolines_toast_zooms_1_10")];
|
||||
break;
|
||||
case MWMMapOverlayIsolinesStateExpiredData:
|
||||
[MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_activation_error_dialog")];
|
||||
[MWMMapOverlayManager setIsoLinesEnabled:NO];
|
||||
break;
|
||||
case MWMMapOverlayIsolinesStateNoData:
|
||||
[MWMAlertViewController.activeAlertController presentInfoAlert:L(@"isolines_location_error_dialog")];
|
||||
[MWMMapOverlayManager setIsoLinesEnabled:NO];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applyTheme {
|
||||
MWMButton *btn = static_cast<MWMButton *>(self.view);
|
||||
UIImageView *iv = btn.imageView;
|
||||
|
||||
// Traffic state machine: https://confluence.mail.ru/pages/viewpage.action?pageId=103680959
|
||||
[iv stopAnimating];
|
||||
if ([MWMMapOverlayManager trafficEnabled]) {
|
||||
[self handleTrafficState:[MWMMapOverlayManager trafficState]];
|
||||
} else if ([MWMMapOverlayManager transitEnabled]) {
|
||||
btn.imageName = @"btn_subway_on";
|
||||
if ([MWMMapOverlayManager transitState] == MWMMapOverlayTransitStateNoData)
|
||||
[Toast showWithText:L(@"subway_data_unavailable")];
|
||||
} else if ([MWMMapOverlayManager isoLinesEnabled]) {
|
||||
btn.imageName = @"btn_isoMap_on";
|
||||
[self handleIsolinesState:[MWMMapOverlayManager isolinesState]];
|
||||
} else if ([MWMMapOverlayManager outdoorEnabled]) {
|
||||
btn.imageName = @"btn_isoMap_on";
|
||||
} else {
|
||||
btn.imageName = @"btn_layers";
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)buttonTouchUpInside {
|
||||
BOOL needsToDisableMapLayer =
|
||||
[MWMMapOverlayManager trafficEnabled] ||
|
||||
[MWMMapOverlayManager transitEnabled] ||
|
||||
[MWMMapOverlayManager isoLinesEnabled] ||
|
||||
[MWMMapOverlayManager outdoorEnabled];
|
||||
|
||||
if (needsToDisableMapLayer) {
|
||||
[MWMMapOverlayManager setTrafficEnabled:NO];
|
||||
[MWMMapOverlayManager setTransitEnabled:NO];
|
||||
[MWMMapOverlayManager setIsoLinesEnabled:NO];
|
||||
[MWMMapOverlayManager setOutdoorEnabled:NO];
|
||||
} else {
|
||||
MWMMapViewControlsManager.manager.menuState = MWMBottomMenuStateLayers;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)updateAvailableArea:(CGRect)frame {
|
||||
auto controller = [self controller];
|
||||
if (CGRectEqualToRect(controller.availableArea, frame))
|
||||
return;
|
||||
controller.availableArea = frame;
|
||||
[controller refreshLayout];
|
||||
}
|
||||
|
||||
#pragma mark - MWMMapOverlayManagerObserver
|
||||
|
||||
- (void)onTrafficStateUpdated {
|
||||
[self applyTheme];
|
||||
}
|
||||
- (void)onTransitStateUpdated {
|
||||
[self applyTheme];
|
||||
}
|
||||
- (void)onIsoLinesStateUpdated {
|
||||
[self applyTheme];
|
||||
}
|
||||
- (void)onOutdoorStateUpdated {
|
||||
[self applyTheme];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<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="MWMTrafficButtonViewController">
|
||||
<connections>
|
||||
<outlet property="view" destination="WVx-0E-RoH" id="0Ev-19-Sxq"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WVx-0E-RoH" customClass="MWMButton" propertyAccessControl="all">
|
||||
<rect key="frame" x="0.0" y="0.0" width="56" height="56"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="layers_button"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="56" id="24f-V4-Vuf"/>
|
||||
<constraint firstAttribute="width" constant="56" id="hko-xz-hRz"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="iUc-A7-STp"/>
|
||||
<state key="normal" image="btn_traffic_on_light"/>
|
||||
<connections>
|
||||
<action selector="buttonTouchUpInside" destination="-1" eventType="touchUpInside" id="fKZ-g8-4ML"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="0.0" y="0.0"/>
|
||||
</button>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="btn_traffic_on_light" width="56" height="56"/>
|
||||
</resources>
|
||||
</document>
|
||||
Loading…
Add table
Add a link
Reference in a new issue