[MAPSME-5825] [ios] Added transport navigation support.

This commit is contained in:
Ilya Grechuhin 2017-11-22 17:06:59 +03:00 committed by Roman Kuznetsov
parent 85e6baf264
commit 2eebdd203b
25 changed files with 1319 additions and 391 deletions

View file

@ -45,6 +45,7 @@
#import "MWMRouteManagerPointType.h"
#import "MWMRoutePreviewTaxiCellType.h"
#import "MWMRouter.h"
#import "MWMRouterTransitStepInfo.h"
#import "MWMSearchItemType.h"
#import "MWMSearchNoResults.h"
#import "MWMSettings.h"

View file

@ -1,5 +1,8 @@
@class MWMRouterTransitStepInfo;
@interface MWMNavigationDashboardEntity : NSObject
@property(copy, nonatomic, readonly) NSArray<MWMRouterTransitStepInfo *> * transitSteps;
@property(copy, nonatomic, readonly) NSAttributedString * estimate;
@property(copy, nonatomic, readonly) NSAttributedString * estimateDot;
@property(copy, nonatomic, readonly) NSString * distanceToTurn;

View file

@ -1,6 +1,7 @@
#import "MWMNavigationDashboardEntity.h"
#import "MWMCoreUnits.h"
#import "MWMLocationManager.h"
#import "MWMRouterTransitStepInfo.h"
#import "MWMSettings.h"
#import "SwiftBridge.h"
@ -8,6 +9,7 @@
@interface MWMNavigationDashboardEntity ()
@property(copy, nonatomic, readwrite) NSArray<MWMRouterTransitStepInfo *> * transitSteps;
@property(copy, nonatomic, readwrite) NSAttributedString * estimate;
@property(copy, nonatomic, readwrite) NSAttributedString * estimateDot;
@property(copy, nonatomic, readwrite) NSString * distanceToTurn;

View file

@ -5,8 +5,11 @@ namespace location
class FollowingInfo;
}
struct TransitRouteInfo;
@interface MWMNavigationDashboardManager (Entity)
- (void)updateFollowingInfo:(location::FollowingInfo const &)info;
- (void)updateTransitInfo:(TransitRouteInfo const &)info;
@end

View file

@ -2,10 +2,13 @@
#import "MWMNavigationDashboardEntity.h"
#import "MWMNavigationDashboardManager+Entity.h"
#import "MWMRouter.h"
#import "MWMRouterTransitStepInfo.h"
#import "SwiftBridge.h"
#include "routing/turns.hpp"
#include "map/routing_manager.hpp"
#include "platform/location.hpp"
#include "geometry/distance_on_sphere.hpp"
@ -45,10 +48,44 @@ UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
return nil;
return [UIImage imageNamed:isNextTurn ? [imageName stringByAppendingString:@"_then"] : imageName];
}
NSAttributedString * estimate(NSTimeInterval time, NSAttributedString * dot, NSString * distance,
NSString * distanceUnits, NSDictionary * primaryAttributes,
NSDictionary * secondaryAttributes, BOOL isWalk)
{
NSString * eta = [NSDateComponentsFormatter etaStringFrom:time];
auto result = [[NSMutableAttributedString alloc] initWithString:eta attributes:primaryAttributes];
[result appendAttributedString:dot];
if (isWalk)
{
UIFont * font = primaryAttributes[NSFontAttributeName];
auto textAttachment = [[NSTextAttachment alloc] init];
auto image = [UIImage imageNamed:@"ic_walk"];
textAttachment.image = image;
auto const height = font.lineHeight;
auto const y = height - image.size.height;
auto const width = image.size.width * height / image.size.height;
textAttachment.bounds = CGRectIntegral({{0, y}, {width, height}});
NSMutableAttributedString * attrStringWithImage =
[NSAttributedString attributedStringWithAttachment:textAttachment].mutableCopy;
[attrStringWithImage addAttributes:secondaryAttributes
range:NSMakeRange(0, attrStringWithImage.length)];
[result appendAttributedString:attrStringWithImage];
}
auto target = [NSString stringWithFormat:@"%@ %@", distance, distanceUnits];
[result appendAttributedString:[[NSAttributedString alloc] initWithString:target
attributes:secondaryAttributes]];
return result;
}
} // namespace
@interface MWMNavigationDashboardEntity ()
@property(copy, nonatomic, readwrite) NSArray<MWMRouterTransitStepInfo *> * transitSteps;
@property(copy, nonatomic, readwrite) NSAttributedString * estimate;
@property(copy, nonatomic, readwrite) NSString * distanceToTurn;
@property(copy, nonatomic, readwrite) NSString * streetName;
@ -65,9 +102,16 @@ UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
@end
@interface MWMRouterTransitStepInfo ()
- (instancetype)initWithStepInfo:(TransitStepInfo const &)info;
@end
@interface MWMNavigationDashboardManager ()
@property(copy, nonatomic) NSDictionary * etaAttributes;
@property(copy, nonatomic) NSDictionary * etaSecondaryAttributes;
@property(nonatomic) MWMNavigationDashboardEntity * entity;
- (void)onNavigationInfoUpdated;
@ -87,7 +131,7 @@ UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
if (auto entity = self.entity)
{
entity.isValid = info.IsValid();
entity.isValid = YES;
entity.timeToTarget = info.m_time;
entity.targetDistance = @(info.m_distToTarget.c_str());
entity.targetUnits = @(info.m_targetUnitsSuffix.c_str());
@ -97,12 +141,9 @@ UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
entity.streetName = @(info.m_displayedStreetName.c_str());
entity.nextTurnImage = image(info.m_nextTurn, true);
NSString * eta = [NSDateComponentsFormatter etaStringFrom:entity.timeToTarget];
auto result = [[NSMutableAttributedString alloc] initWithString:eta attributes:self.etaAttributes];
[result appendAttributedString:entity.estimateDot];
auto target = [NSString stringWithFormat:@"%@ %@", entity.targetDistance, entity.targetUnits];
[result appendAttributedString:[[NSAttributedString alloc] initWithString:target attributes:self.etaAttributes]];
entity.estimate = result;
entity.estimate =
estimate(entity.timeToTarget, entity.estimateDot, entity.targetDistance, entity.targetUnits,
self.etaAttributes, self.etaSecondaryAttributes, NO);
using namespace routing::turns;
CarDirection const turn = info.m_turn;
@ -119,4 +160,21 @@ UIImage * image(routing::turns::CarDirection t, bool isNextTurn)
[self onNavigationInfoUpdated];
}
- (void)updateTransitInfo:(TransitRouteInfo const &)info
{
if (auto entity = self.entity)
{
entity.isValid = YES;
entity.estimate = estimate(info.m_totalTimeInSec, entity.estimateDot,
@(info.m_totalPedestrianDistanceStr.c_str()),
@(info.m_totalPedestrianUnitsSuffix.c_str()), self.etaAttributes,
self.etaSecondaryAttributes, YES);
NSMutableArray<MWMRouterTransitStepInfo *> * transitSteps = [@[] mutableCopy];
for (auto const & stepInfo : info.m_steps)
[transitSteps addObject:[[MWMRouterTransitStepInfo alloc] initWithStepInfo:stepInfo]];
entity.transitSteps = transitSteps;
}
[self onNavigationInfoUpdated];
}
@end

View file

@ -31,11 +31,13 @@ using Observers = NSHashTable<Observer>;
@interface MWMNavigationDashboardManager ()<MWMSearchManagerObserver>
@property(copy, nonatomic) NSDictionary * etaAttributes;
@property(copy, nonatomic) NSDictionary * etaSecondaryAttributes;
@property(copy, nonatomic) NSString * errorMessage;
@property(nonatomic) IBOutlet MWMBaseRoutePreviewStatus * baseRoutePreviewStatus;
@property(nonatomic) IBOutlet MWMNavigationControlView * navigationControlView;
@property(nonatomic) IBOutlet MWMNavigationInfoView * navigationInfoView;
@property(nonatomic) IBOutlet MWMRoutePreview * routePreview;
@property(nonatomic) IBOutlet MWMRoutePreviewStatus * statusBox;
@property(nonatomic) IBOutlet MWMTransportRoutePreviewStatus * transportRoutePreviewStatus;
@property(nonatomic) IBOutletCollection(MWMRouteStartButton) NSArray * goButtons;
@property(nonatomic) MWMNavigationDashboardEntity * entity;
@property(nonatomic) MWMRouteManagerTransitioningManager * routeManagerTransitioningManager;
@ -43,6 +45,7 @@ using Observers = NSHashTable<Observer>;
@property(nonatomic, readwrite) MWMTaxiPreviewDataSource * taxiDataSource;
@property(weak, nonatomic) IBOutlet MWMTaxiCollectionView * taxiCollectionView;
@property(weak, nonatomic) IBOutlet UIButton * showRouteManagerButton;
@property(weak, nonatomic) IBOutlet UIView * goButtonsContainer;
@property(weak, nonatomic) UIView * ownerView;
@end
@ -65,12 +68,14 @@ using Observers = NSHashTable<Observer>;
return self;
}
- (void)loadPreviewWithStatusBox
- (void)loadPreviewWithStatusBoxes
{
[NSBundle.mainBundle loadNibNamed:IPAD ? kRoutePreviewIPADXibName : kRoutePreviewIPhoneXibName
owner:self
options:nil];
_statusBox.ownerView = self.ownerView;
auto ownerView = self.ownerView;
_baseRoutePreviewStatus.ownerView = ownerView;
_transportRoutePreviewStatus.ownerView = ownerView;
}
#pragma mark - MWMRoutePreview
@ -100,7 +105,8 @@ using Observers = NSHashTable<Observer>;
[_routePreview mwm_refreshUI];
[_navigationInfoView mwm_refreshUI];
[_navigationControlView mwm_refreshUI];
[_statusBox mwm_refreshUI];
[_baseRoutePreviewStatus mwm_refreshUI];
[_transportRoutePreviewStatus mwm_refreshUI];
}
- (void)onNavigationInfoUpdated
@ -109,7 +115,10 @@ using Observers = NSHashTable<Observer>;
if (!entity.isValid)
return;
[_navigationInfoView onNavigationInfoUpdated:entity];
[_statusBox onNavigationInfoUpdated:entity];
if ([MWMRouter type] == MWMRouterTypePublicTransport)
[_transportRoutePreviewStatus onNavigationInfoUpdated:entity];
else
[_baseRoutePreviewStatus onNavigationInfoUpdated:entity];
[_navigationControlView onNavigationInfoUpdated:entity];
}
@ -141,8 +150,10 @@ using Observers = NSHashTable<Observer>;
self.navigationInfoView = nil;
_navigationControlView.isVisible = NO;
_navigationControlView = nil;
[self.statusBox stateHidden];
self.statusBox = nil;
[_baseRoutePreviewStatus hide];
_baseRoutePreviewStatus = nil;
[_transportRoutePreviewStatus hide];
_transportRoutePreviewStatus = nil;
}
- (void)statePrepare
@ -153,7 +164,8 @@ using Observers = NSHashTable<Observer>;
[routePreview statePrepare];
[routePreview selectRouter:[MWMRouter type]];
[self updateGoButtonTitle];
[self.statusBox statePrepare];
[_baseRoutePreviewStatus hide];
[_transportRoutePreviewStatus hide];
for (MWMRouteStartButton * button in self.goButtons)
[button statePrepare];
}
@ -193,7 +205,7 @@ using Observers = NSHashTable<Observer>;
auto routePreview = self.routePreview;
[routePreview router:[MWMRouter type] setState:MWMCircularProgressStateFailed];
[self updateGoButtonTitle];
[self.statusBox stateErrorWithMessage:self.errorMessage];
[self.baseRoutePreviewStatus showErrorWithMessage:self.errorMessage];
for (MWMRouteStartButton * button in self.goButtons)
[button stateError];
}
@ -203,7 +215,12 @@ using Observers = NSHashTable<Observer>;
NSAssert(_state == MWMNavigationDashboardStatePlanning, @"Invalid state change (ready)");
[self setRouteBuilderProgress:100.];
[self updateGoButtonTitle];
[self.statusBox stateReady];
auto const isTransport = ([MWMRouter type] == MWMRouterTypePublicTransport);
if (isTransport)
[self.transportRoutePreviewStatus showReady];
else
[self.baseRoutePreviewStatus showReady];
self.goButtonsContainer.hidden = isTransport;
for (MWMRouteStartButton * button in self.goButtons)
[button stateReady];
}
@ -216,8 +233,10 @@ using Observers = NSHashTable<Observer>;
self.routePreview = nil;
self.navigationInfoView.state = MWMNavigationInfoViewStateNavigation;
self.navigationControlView.isVisible = YES;
[self.statusBox stateNavigation];
self.statusBox = nil;
[_baseRoutePreviewStatus hide];
_baseRoutePreviewStatus = nil;
[_transportRoutePreviewStatus hide];
_transportRoutePreviewStatus = nil;
[self onNavigationInfoUpdated];
}
@ -318,6 +337,18 @@ using Observers = NSHashTable<Observer>;
return _etaAttributes;
}
- (NSDictionary *)etaSecondaryAttributes
{
if (!_etaSecondaryAttributes)
{
_etaSecondaryAttributes = @{
NSForegroundColorAttributeName: [UIColor blackSecondaryText],
NSFontAttributeName: [UIFont medium17]
};
}
return _etaSecondaryAttributes;
}
- (void)setState:(MWMNavigationDashboardState)state
{
if (_state == state)
@ -351,15 +382,22 @@ using Observers = NSHashTable<Observer>;
- (MWMRoutePreview *)routePreview
{
if (!_routePreview)
[self loadPreviewWithStatusBox];
[self loadPreviewWithStatusBoxes];
return _routePreview;
}
- (MWMRoutePreviewStatus *)statusBox
- (MWMBaseRoutePreviewStatus *)baseRoutePreviewStatus
{
if (!_statusBox)
[self loadPreviewWithStatusBox];
return _statusBox;
if (!_baseRoutePreviewStatus)
[self loadPreviewWithStatusBoxes];
return _baseRoutePreviewStatus;
}
- (MWMTransportRoutePreviewStatus *)transportRoutePreviewStatus
{
if (!_transportRoutePreviewStatus)
[self loadPreviewWithStatusBoxes];
return _transportRoutePreviewStatus;
}
- (MWMNavigationInfoView *)navigationInfoView

View file

@ -17,10 +17,12 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMNavigationDashboardManager">
<connections>
<outlet property="baseRoutePreviewStatus" destination="87p-Qg-8f3" id="ddh-nm-Ux9"/>
<outlet property="goButtonsContainer" destination="gcR-zj-b7P" id="RuF-Qu-ahX"/>
<outlet property="routePreview" destination="u2u-Vb-2eH" id="VZw-5q-2P6"/>
<outlet property="showRouteManagerButton" destination="NAs-km-8uw" id="pJx-0l-Skz"/>
<outlet property="statusBox" destination="87p-Qg-8f3" id="dze-gL-fnK"/>
<outlet property="taxiCollectionView" destination="t6d-gI-JcN" id="b5y-vn-rwV"/>
<outlet property="transportRoutePreviewStatus" destination="FXb-tH-ZTF" id="P0g-ys-6wW"/>
<outletCollection property="goButtons" destination="4IJ-pR-Ztp" id="ePc-jh-SfE"/>
</connections>
</placeholder>
@ -127,7 +129,7 @@
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="primary"/>
</userDefinedRuntimeAttributes>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="87p-Qg-8f3" userLabel="Status Box" customClass="MWMRoutePreviewStatus">
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="87p-Qg-8f3" customClass="MWMBaseRoutePreviewStatus">
<rect key="frame" x="0.0" y="100" width="375" height="180"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QEP-6s-YTM" userLabel="Error Box">
@ -354,6 +356,49 @@
<outlet property="taxiBoxBottom" destination="CCT-23-3wk" id="e2w-eO-HqA"/>
</connections>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FXb-tH-ZTF" customClass="MWMTransportRoutePreviewStatus">
<rect key="frame" x="0.0" y="100" width="375" height="80"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tuZ-25-ltG">
<rect key="frame" x="16" y="12" width="42" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<collectionView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" alwaysBounceHorizontal="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" delaysContentTouches="NO" canCancelContentTouches="NO" bouncesZoom="NO" dataMode="none" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Ey-lL-uzF" customClass="TransportTransitStepsCollectionView" customModule="cm_dbg" customModuleProvider="target">
<rect key="frame" x="16" y="44" width="343" height="20"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="4NI-xp-o3L"/>
</constraints>
<collectionViewLayout key="collectionViewLayout" id="PJv-Hi-Xu3" customClass="TransportTransitFlowLayout" customModule="cm_dbg" customModuleProvider="target"/>
</collectionView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="tuZ-25-ltG" firstAttribute="top" secondItem="FXb-tH-ZTF" secondAttribute="top" constant="12" id="1Aj-rm-MMr"/>
<constraint firstItem="8Ey-lL-uzF" firstAttribute="top" secondItem="tuZ-25-ltG" secondAttribute="bottom" constant="12" id="CKR-P5-B2a"/>
<constraint firstItem="tuZ-25-ltG" firstAttribute="leading" secondItem="FXb-tH-ZTF" secondAttribute="leading" constant="16" id="GJC-Gt-255"/>
<constraint firstAttribute="bottom" secondItem="8Ey-lL-uzF" secondAttribute="bottom" constant="16" id="KxL-xf-eVL"/>
<constraint firstAttribute="trailing" secondItem="8Ey-lL-uzF" secondAttribute="trailing" constant="16" id="ejR-Po-Dxm"/>
<constraint firstItem="8Ey-lL-uzF" firstAttribute="leading" secondItem="tuZ-25-ltG" secondAttribute="leading" id="gkU-xQ-hb2"/>
<constraint firstAttribute="height" priority="100" constant="80" id="lLi-5o-PDI"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor">
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="etaLabel" destination="tuZ-25-ltG" id="Rwo-UC-mvq"/>
<outlet property="stepsCollectionView" destination="8Ey-lL-uzF" id="qrI-Cw-rAJ"/>
<outlet property="stepsCollectionViewHeight" destination="4NI-xp-o3L" id="Z11-UU-Mca"/>
</connections>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gcR-zj-b7P">
<rect key="frame" x="0.0" y="619" width="375" height="48"/>
<subviews>
@ -402,13 +447,16 @@
<constraint firstAttribute="trailing" secondItem="87p-Qg-8f3" secondAttribute="trailing" id="5wh-lx-rUz"/>
<constraint firstItem="3s2-BV-X5i" firstAttribute="top" secondItem="3zr-me-gbI" secondAttribute="bottom" id="6c0-tH-qlJ"/>
<constraint firstItem="87p-Qg-8f3" firstAttribute="top" secondItem="3s2-BV-X5i" secondAttribute="bottom" constant="36" id="8nt-tf-wyq"/>
<constraint firstItem="FXb-tH-ZTF" firstAttribute="top" secondItem="3s2-BV-X5i" secondAttribute="bottom" constant="36" id="9Bz-NL-px6"/>
<constraint firstItem="87p-Qg-8f3" firstAttribute="leading" secondItem="u2u-Vb-2eH" secondAttribute="leading" id="9bA-9R-pwq"/>
<constraint firstItem="FXb-tH-ZTF" firstAttribute="leading" secondItem="u2u-Vb-2eH" secondAttribute="leading" id="Mmr-RH-iDm"/>
<constraint firstAttribute="trailing" secondItem="3zr-me-gbI" secondAttribute="trailing" id="OZ2-dP-mna"/>
<constraint firstAttribute="bottom" secondItem="gcR-zj-b7P" secondAttribute="bottom" id="QYs-r4-Jyl"/>
<constraint firstItem="3s2-BV-X5i" firstAttribute="leading" secondItem="u2u-Vb-2eH" secondAttribute="leading" id="e90-R4-YQR"/>
<constraint firstItem="3zr-me-gbI" firstAttribute="top" secondItem="u2u-Vb-2eH" secondAttribute="top" id="hE5-50-mMA"/>
<constraint firstAttribute="trailing" secondItem="3s2-BV-X5i" secondAttribute="trailing" id="lnu-7l-aPG"/>
<constraint firstAttribute="trailing" secondItem="gcR-zj-b7P" secondAttribute="trailing" id="n9j-dG-kOB"/>
<constraint firstAttribute="trailing" secondItem="FXb-tH-ZTF" secondAttribute="trailing" id="sFK-Dz-Ta2"/>
<constraint firstItem="3zr-me-gbI" firstAttribute="leading" secondItem="u2u-Vb-2eH" secondAttribute="leading" id="xgY-7G-jgv"/>
</constraints>
<userDefinedRuntimeAttributes>

View file

@ -16,9 +16,10 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMNavigationDashboardManager">
<connections>
<outlet property="baseRoutePreviewStatus" destination="hIE-BJ-nFm" id="Kwy-sL-krz"/>
<outlet property="routePreview" destination="aNH-vh-DPz" id="ORz-pz-7sV"/>
<outlet property="statusBox" destination="hIE-BJ-nFm" id="j6g-xk-RgK"/>
<outlet property="taxiCollectionView" destination="Dm8-yS-U68" id="crw-jv-vGq"/>
<outlet property="transportRoutePreviewStatus" destination="iWi-pM-AJF" id="ah9-rm-QeN"/>
<outletCollection property="goButtons" destination="ZXz-KM-xQz" id="14O-qB-UJl"/>
<outletCollection property="goButtons" destination="CQB-xn-DSM" id="FPU-6h-5CN"/>
</connections>
@ -157,7 +158,7 @@
</connections>
<point key="canvasLocation" x="448" y="341"/>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hIE-BJ-nFm" userLabel="Status Box" customClass="MWMRoutePreviewStatus">
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hIE-BJ-nFm" customClass="MWMBaseRoutePreviewStatus">
<rect key="frame" x="0.0" y="0.0" width="320" height="152"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fD2-1N-x27" userLabel="Error Box">
@ -396,7 +397,7 @@
<outlet property="manageRouteBoxBottom" destination="kPq-9v-D4c" id="FPP-Hc-DGv"/>
<outlet property="manageRouteButtonCompact" destination="Zzm-Yo-BvL" id="MAs-VL-pR0"/>
<outlet property="manageRouteButtonRegular" destination="K37-2W-GE8" id="I40-pl-MM4"/>
<outlet property="resultLabel" destination="sjQ-Sc-mtN" id="XIY-sS-M2V"/>
<outlet property="resultLabel" destination="sjQ-Sc-mtN" id="GLa-P4-7XO"/>
<outlet property="resultsBox" destination="Tai-sE-6DC" id="l4p-m2-z4z"/>
<outlet property="resultsBoxBottom" destination="trf-mi-xeb" id="tdb-sa-2ak"/>
<outlet property="taxiBox" destination="5a5-vb-p6T" id="MLv-mh-dK2"/>
@ -404,6 +405,51 @@
</connections>
<point key="canvasLocation" x="448" y="521"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iWi-pM-AJF" customClass="MWMTransportRoutePreviewStatus">
<rect key="frame" x="0.0" y="0.0" width="320" height="80"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iu4-M8-t6g">
<rect key="frame" x="16" y="12" width="42" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<collectionView userInteractionEnabled="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" alwaysBounceHorizontal="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" delaysContentTouches="NO" canCancelContentTouches="NO" bouncesZoom="NO" dataMode="none" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RVh-LF-kSn" customClass="TransportTransitStepsCollectionView" customModule="cm_dbg" customModuleProvider="target">
<rect key="frame" x="16" y="44" width="288" height="20"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="eGu-Mr-auv"/>
</constraints>
<collectionViewLayout key="collectionViewLayout" id="d3P-nT-IFD" customClass="TransportTransitFlowLayout" customModule="cm_dbg" customModuleProvider="target"/>
</collectionView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Iu4-M8-t6g" firstAttribute="leading" secondItem="iWi-pM-AJF" secondAttribute="leading" constant="16" id="5Ge-fx-3pw"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="80" id="CQk-tf-wu9"/>
<constraint firstItem="RVh-LF-kSn" firstAttribute="top" secondItem="Iu4-M8-t6g" secondAttribute="bottom" constant="12" id="DOH-Jl-zYW"/>
<constraint firstItem="RVh-LF-kSn" firstAttribute="leading" secondItem="Iu4-M8-t6g" secondAttribute="leading" id="Jo0-dN-03y"/>
<constraint firstItem="Iu4-M8-t6g" firstAttribute="top" secondItem="iWi-pM-AJF" secondAttribute="top" constant="12" id="Zyw-PT-55a"/>
<constraint firstAttribute="bottom" secondItem="RVh-LF-kSn" secondAttribute="bottom" constant="16" id="b0R-Xj-EVN"/>
<constraint firstAttribute="trailing" secondItem="RVh-LF-kSn" secondAttribute="trailing" constant="16" id="nhh-en-tgm"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor">
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="etaLabel" destination="Iu4-M8-t6g" id="hJe-KS-ctT"/>
<outlet property="stepsCollectionView" destination="RVh-LF-kSn" id="3uG-nE-mt3"/>
<outlet property="stepsCollectionViewHeight" destination="eGu-Mr-auv" id="K2J-yO-yQ5"/>
</connections>
<point key="canvasLocation" x="449" y="737"/>
</view>
</objects>
<resources>
<image name="ic_24px_manager" width="24" height="24"/>

View file

@ -1,5 +1,5 @@
@objc(MWMRoutePreviewStatus)
final class RoutePreviewStatus: SolidTouchView {
@objc(MWMBaseRoutePreviewStatus)
final class BaseRoutePreviewStatus: SolidTouchView {
@IBOutlet private weak var errorBox: UIView!
@IBOutlet private weak var resultsBox: UIView!
@IBOutlet private weak var heightBox: UIView!
@ -49,7 +49,7 @@ final class RoutePreviewStatus: SolidTouchView {
}
}
var isVisible = false {
private var isVisible = false {
didSet {
alternative(iPhone: {
guard self.isVisible != oldValue else { return }
@ -120,15 +120,11 @@ final class RoutePreviewStatus: SolidTouchView {
manageRouteButtonCompact?.isHidden = !isCompact
}
@objc func stateHidden() {
@objc func hide() {
isVisible = false
}
@objc func statePrepare() {
isVisible = false
}
@objc func stateError(message: String) {
@objc func showError(message: String) {
isVisible = true
errorBox.isHidden = false
resultsBox.isHidden = true
@ -141,7 +137,7 @@ final class RoutePreviewStatus: SolidTouchView {
updateHeight()
}
@objc func stateReady() {
@objc func showReady() {
isVisible = true
errorBox.isHidden = true
@ -175,10 +171,6 @@ final class RoutePreviewStatus: SolidTouchView {
updateHeight()
}
@objc func stateNavigation() {
isVisible = false
}
private func updateResultsLabel() {
guard let info = navigationInfo else { return }

View file

@ -0,0 +1,97 @@
@objc(MWMTransportRoutePreviewStatus)
final class TransportRoutePreviewStatus: SolidTouchView {
@IBOutlet private weak var etaLabel: UILabel!
@IBOutlet private weak var stepsCollectionView: TransportTransitStepsCollectionView!
@IBOutlet private weak var stepsCollectionViewHeight: NSLayoutConstraint!
private var hiddenConstraint: NSLayoutConstraint!
@objc weak var ownerView: UIView!
weak var navigationInfo: MWMNavigationDashboardEntity?
private var isVisible = false {
didSet {
alternative(iPhone: {
guard self.isVisible != oldValue else { return }
if self.isVisible {
self.addView()
}
DispatchQueue.main.async {
guard let sv = self.superview else { return }
sv.setNeedsLayout()
self.hiddenConstraint.isActive = !self.isVisible
UIView.animate(withDuration: kDefaultAnimationDuration,
animations: { sv.layoutIfNeeded() },
completion: { _ in
if !self.isVisible {
self.removeFromSuperview()
}
})
}
},
iPad: { self.isHidden = !self.isVisible })()
}
}
private func addView() {
guard superview != ownerView else { return }
ownerView.addSubview(self)
NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: ownerView, attribute: .left, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: ownerView, attribute: .right, multiplier: 1, constant: 0).isActive = true
hiddenConstraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: ownerView, attribute: .bottom, multiplier: 1, constant: 0)
hiddenConstraint.priority = UILayoutPriority.defaultHigh
hiddenConstraint.isActive = true
let visibleConstraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: ownerView, attribute: .bottom, multiplier: 1, constant: 0)
visibleConstraint.priority = UILayoutPriority.defaultLow
visibleConstraint.isActive = true
}
@objc func hide() {
isVisible = false
}
@objc func showReady() {
isVisible = true
updateHeight()
}
@objc func onNavigationInfoUpdated(_ info: MWMNavigationDashboardEntity) {
navigationInfo = info
etaLabel.attributedText = info.estimate
stepsCollectionView.steps = info.transitSteps
}
private func updateHeight() {
guard stepsCollectionViewHeight.constant != stepsCollectionView.contentSize.height else { return }
DispatchQueue.main.async {
self.setNeedsLayout()
self.stepsCollectionViewHeight.constant = self.stepsCollectionView.contentSize.height
UIView.animate(withDuration: kDefaultAnimationDuration) { self.layoutIfNeeded() }
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateHeight()
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
updateHeight()
}
override var sideButtonsAreaAffectDirections: MWMAvailableAreaAffectDirections {
return alternative(iPhone: .bottom, iPad: [])
}
override var visibleAreaAffectDirections: MWMAvailableAreaAffectDirections {
return alternative(iPhone: .bottom, iPad: [])
}
override var widgetsAreaAffectDirections: MWMAvailableAreaAffectDirections {
return alternative(iPhone: .bottom, iPad: [])
}
}

View file

@ -0,0 +1,11 @@
class TransportTransitCell: UICollectionViewCell {
enum Config {
static let cellSize = CGSize(width: 20, height: 20)
}
class func estimatedCellSize(step _: MWMRouterTransitStepInfo) -> CGSize {
return Config.cellSize
}
func config(step _: MWMRouterTransitStepInfo) {}
}

View file

@ -0,0 +1,77 @@
final class TransportTransitFlowLayout: UICollectionViewLayout {
enum Config {
static let lineSpacing = CGFloat(8)
static let separator = TransportTransitSeparator.self
static let separatorKind = toString(separator)
static let separatorSize = CGSize(width: 16, height: 20)
static let minimumCellWidthAfterShrink = CGFloat(56)
}
private var cellsLayoutAttrs = [UICollectionViewLayoutAttributes]()
private var decoratorsLayoutAttrs = [UICollectionViewLayoutAttributes]()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
register(Config.separator, forDecorationViewOfKind: Config.separatorKind)
}
override var collectionViewContentSize: CGSize {
let width = collectionView?.frame.width ?? 0
let height = cellsLayoutAttrs.reduce(0) { return max($0, $1.frame.maxY) }
return CGSize(width: width, height: height)
}
override func prepare() {
super.prepare()
let cv = collectionView as! TransportTransitStepsCollectionView
let section = 0
let width = cv.width
var x = CGFloat(0)
var y = CGFloat(0)
cellsLayoutAttrs = []
decoratorsLayoutAttrs = []
for item in 0 ..< cv.numberOfItems(inSection: section) {
let ip = IndexPath(item: item, section: section)
if item != 0 {
let sepAttr = UICollectionViewLayoutAttributes(forDecorationViewOfKind: Config.separatorKind, with: ip)
sepAttr.frame = CGRect(origin: CGPoint(x: x, y: y), size: Config.separatorSize)
decoratorsLayoutAttrs.append(sepAttr)
x += Config.separatorSize.width
}
var cellSize = cv.estimatedCellSize(item: item)
let spaceLeft = width - x - Config.separatorSize.width
let minimumSpaceRequired = min(cellSize.width, Config.minimumCellWidthAfterShrink)
if spaceLeft < minimumSpaceRequired {
x = 0
y += Config.separatorSize.height + Config.lineSpacing
} else {
cellSize.width = min(cellSize.width, spaceLeft)
}
let cellAttr = UICollectionViewLayoutAttributes(forCellWith: ip)
cellAttr.frame = CGRect(origin: CGPoint(x: x, y: y), size: cellSize)
cellsLayoutAttrs.append(cellAttr)
x += cellSize.width
}
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellsLayoutAttrs.first(where: { $0.indexPath == indexPath })
}
override func layoutAttributesForDecorationView(ofKind _: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return decoratorsLayoutAttrs.first(where: { $0.indexPath == indexPath })
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttrs = cellsLayoutAttrs.filter { $0.frame.intersects(rect) }
layoutAttrs.append(contentsOf: decoratorsLayoutAttrs.filter { $0.frame.intersects(rect) })
return layoutAttrs
}
}

View file

@ -0,0 +1,17 @@
final class TransportTransitIntermediatePoint: TransportTransitCell {
enum Config {
static let imageColor = UIColor.primary()!
}
@IBOutlet private weak var image: UIImageView!
override func config(step: MWMRouterTransitStepInfo) {
super.config(step: step)
switch step.intermediateIndex {
case 0: image.image = #imageLiteral(resourceName: "ic_route_manager_stop_a")
case 1: image.image = #imageLiteral(resourceName: "ic_route_manager_stop_b")
case 2: image.image = #imageLiteral(resourceName: "ic_route_manager_stop_c")
default: fatalError("Unsupported route point intermediateIndex.")
}
image.tintColor = Config.imageColor
}
}

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="TransportTransitIntermediatePoint" customModule="cm_dbg" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_route_manager_stop_a" translatesAutoresizingMaskIntoConstraints="NO" id="kZf-7J-OZ5">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<color key="tintColor" red="0.1215686275" green="0.59999999999999998" blue="0.32156862749999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="OkK-UD-TWr"/>
<constraint firstAttribute="height" constant="20" id="n8x-xG-gUb"/>
</constraints>
</imageView>
</subviews>
</view>
<constraints>
<constraint firstItem="kZf-7J-OZ5" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="5rb-Q4-qua"/>
<constraint firstAttribute="bottom" secondItem="kZf-7J-OZ5" secondAttribute="bottom" id="5uG-SP-l0m"/>
<constraint firstItem="kZf-7J-OZ5" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="KiE-6N-4Jp"/>
<constraint firstAttribute="trailing" secondItem="kZf-7J-OZ5" secondAttribute="trailing" id="mJI-lD-bsw"/>
</constraints>
<size key="customSize" width="490" height="20"/>
<connections>
<outlet property="image" destination="kZf-7J-OZ5" id="b9M-uB-XoA"/>
</connections>
<point key="canvasLocation" x="270" y="54"/>
</collectionViewCell>
</objects>
<resources>
<image name="ic_route_manager_stop_a" width="24" height="24"/>
</resources>
</document>

View file

@ -0,0 +1,22 @@
final class TransportTransitPedestrian: TransportTransitCell {
enum Config {
static let backgroundCornerRadius = CGFloat(4)
static let backgroundColor = UIColor.blackOpaque()!
static let imageColor = UIColor.blackSecondaryText()!
}
@IBOutlet private weak var background: UIView! {
didSet {
background.layer.cornerRadius = Config.backgroundCornerRadius
background.backgroundColor = Config.backgroundColor
}
}
@IBOutlet private weak var image: UIImageView! {
didSet {
image.image = #imageLiteral(resourceName: "ic_walk")
image.tintColor = Config.imageColor
image.contentMode = .scaleAspectFit
}
}
}

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="gTV-IL-0wX" customClass="TransportTransitPedestrian" customModule="cm_dbg" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Shb-td-cXL">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" image="ic_walk" translatesAutoresizingMaskIntoConstraints="NO" id="9hI-Y9-uRa">
<rect key="frame" x="3" y="3" width="14" height="14"/>
<constraints>
<constraint firstAttribute="width" constant="14" id="EeL-qS-rKg"/>
<constraint firstAttribute="height" constant="14" id="WCk-l4-hQF"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="9hI-Y9-uRa" firstAttribute="centerY" secondItem="Shb-td-cXL" secondAttribute="centerY" id="IkJ-Yh-48o"/>
<constraint firstAttribute="height" constant="20" id="hEu-YE-u8j"/>
<constraint firstAttribute="width" constant="20" id="pxM-8S-VsE"/>
<constraint firstItem="9hI-Y9-uRa" firstAttribute="centerX" secondItem="Shb-td-cXL" secondAttribute="centerX" id="vZX-k3-HmM"/>
</constraints>
</view>
</subviews>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="Shb-td-cXL" secondAttribute="trailing" id="JRQ-z7-d3U"/>
<constraint firstAttribute="bottom" secondItem="Shb-td-cXL" secondAttribute="bottom" id="nDY-rn-9J0"/>
<constraint firstItem="Shb-td-cXL" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="pu1-LW-wkd"/>
<constraint firstItem="Shb-td-cXL" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="ymH-iI-Ify"/>
</constraints>
<size key="customSize" width="227" height="20"/>
<connections>
<outlet property="background" destination="Shb-td-cXL" id="YAM-iA-NYW"/>
<outlet property="image" destination="9hI-Y9-uRa" id="9i8-eW-XWO"/>
</connections>
<point key="canvasLocation" x="137.5" y="54"/>
</collectionViewCell>
</objects>
<resources>
<image name="ic_walk" width="24" height="24"/>
</resources>
</document>

View file

@ -0,0 +1,27 @@
final class TransportTransitSeparator: UICollectionReusableView {
enum Config {
static let imageColor = UIColor.blackSecondaryText()!
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
let image = UIImageView(image: #imageLiteral(resourceName: "ic_arrow"))
image.tintColor = Config.imageColor
image.contentMode = .scaleAspectFit
addSubview(image)
}
override func layoutSubviews() {
super.layoutSubviews()
subviews.first!.frame = bounds
}
}

View file

@ -0,0 +1,57 @@
final class TransportTransitStepsCollectionView: UICollectionView {
var steps: [MWMRouterTransitStepInfo] = [] {
didSet {
reloadData()
}
}
override var frame: CGRect {
didSet {
collectionViewLayout.invalidateLayout()
}
}
override var bounds: CGRect {
didSet {
collectionViewLayout.invalidateLayout()
}
}
override func awakeFromNib() {
super.awakeFromNib()
dataSource = self
[TransportTransitIntermediatePoint.self, TransportTransitPedestrian.self, TransportTransitTrain.self].forEach {
register(cellClass: $0)
}
}
private func cellClass(item: Int) -> TransportTransitCell.Type {
let step = steps[item]
switch step.type {
case .intermediatePoint: return TransportTransitIntermediatePoint.self
case .pedestrian: return TransportTransitPedestrian.self
case .train: fallthrough
case .subway: fallthrough
case .lightRail: fallthrough
case .monorail: return TransportTransitTrain.self
}
}
func estimatedCellSize(item: Int) -> CGSize {
return cellClass(item: item).estimatedCellSize(step: steps[item])
}
}
extension TransportTransitStepsCollectionView: UICollectionViewDataSource {
func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
return steps.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let item = indexPath.item
let cellClass = self.cellClass(item: item)
let cell = collectionView.dequeueReusableCell(withCellClass: cellClass, indexPath: indexPath) as! TransportTransitCell
cell.config(step: steps[item])
return cell
}
}

View file

@ -0,0 +1,52 @@
final class TransportTransitTrain: TransportTransitCell {
enum Config {
static let backgroundCornerRadius = CGFloat(4)
static let labelTextColor = UIColor.white
static let labelTextFont = UIFont.bold12()!
static let labelTrailing = CGFloat(4)
}
@IBOutlet private weak var background: UIView! {
didSet {
background.layer.cornerRadius = Config.backgroundCornerRadius
}
}
@IBOutlet private weak var image: UIImageView!
@IBOutlet private weak var label: UILabel! {
didSet {
label.textColor = Config.labelTextColor
label.font = Config.labelTextFont
}
}
@IBOutlet private weak var labelTrailing: NSLayoutConstraint! {
didSet {
labelTrailing.constant = Config.labelTrailing
}
}
@IBOutlet private var emptyNumberTrailingOffset: NSLayoutConstraint!
override class func estimatedCellSize(step: MWMRouterTransitStepInfo) -> CGSize {
let defaultSize = super.estimatedCellSize(step: step)
let labelSize = step.number.size(width: CGFloat.greatestFiniteMagnitude, font: Config.labelTextFont, maxNumberOfLines: 1)
return CGSize(width: defaultSize.width + labelSize.width + Config.labelTrailing, height: defaultSize.height)
}
override func config(step: MWMRouterTransitStepInfo) {
switch step.type {
case .intermediatePoint: fallthrough
case .pedestrian: fatalError()
case .train: image.image = #imageLiteral(resourceName: "ic_20px_route_planning_train")
case .subway: fallthrough
case .lightRail: fallthrough
case .monorail: image.image = #imageLiteral(resourceName: "ic_20px_route_planning_metro")
}
background.backgroundColor = step.color
emptyNumberTrailingOffset.isActive = step.number.isEmpty
label.isHidden = step.number.isEmpty
label.text = step.number
}
}

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="TransportTransitTrain" customModule="cm_dbg" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kDc-o2-JUp">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9d1-PP-h28">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" secondItem="9d1-PP-h28" secondAttribute="height" multiplier="1:1" id="g45-u1-mQs"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="450" verticalCompressionResistancePriority="450" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Eo-0D-mup">
<rect key="frame" x="20" y="0.0" width="0.0" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="9d1-PP-h28" firstAttribute="top" secondItem="kDc-o2-JUp" secondAttribute="top" id="3Nm-tA-OCb"/>
<constraint firstItem="0Eo-0D-mup" firstAttribute="leading" secondItem="9d1-PP-h28" secondAttribute="trailing" id="3sb-9G-W6c"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="0Eo-0D-mup" secondAttribute="trailing" priority="750" id="5NZ-eM-6di"/>
<constraint firstAttribute="bottom" secondItem="0Eo-0D-mup" secondAttribute="bottom" id="Gu9-KZ-D9R"/>
<constraint firstAttribute="trailing" secondItem="0Eo-0D-mup" secondAttribute="trailing" priority="250" constant="4" id="YNn-8w-SmG"/>
<constraint firstItem="0Eo-0D-mup" firstAttribute="top" secondItem="kDc-o2-JUp" secondAttribute="top" id="ZPx-f9-8LV"/>
<constraint firstItem="9d1-PP-h28" firstAttribute="leading" secondItem="kDc-o2-JUp" secondAttribute="leading" id="cQu-Lg-9xy"/>
<constraint firstAttribute="bottom" secondItem="9d1-PP-h28" secondAttribute="bottom" id="m4N-mH-YaE"/>
<constraint firstAttribute="trailing" secondItem="9d1-PP-h28" secondAttribute="trailing" id="mCa-Ah-9Xz"/>
<constraint firstAttribute="height" constant="20" id="nQ0-T1-CvV"/>
</constraints>
</view>
</subviews>
</view>
<constraints>
<constraint firstAttribute="bottom" secondItem="kDc-o2-JUp" secondAttribute="bottom" id="3wL-hq-d5s"/>
<constraint firstItem="kDc-o2-JUp" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="JMg-4a-h4Z"/>
<constraint firstItem="kDc-o2-JUp" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="MOo-JD-4vU"/>
<constraint firstAttribute="trailing" secondItem="kDc-o2-JUp" secondAttribute="trailing" id="gmg-yt-uVD"/>
</constraints>
<size key="customSize" width="744" height="20"/>
<connections>
<outlet property="background" destination="kDc-o2-JUp" id="fh8-Ss-FeL"/>
<outlet property="emptyNumberTrailingOffset" destination="mCa-Ah-9Xz" id="k8k-Ca-u6s"/>
<outlet property="image" destination="9d1-PP-h28" id="Kpo-zR-osU"/>
<outlet property="label" destination="0Eo-0D-mup" id="Z15-fa-Wkx"/>
<outlet property="labelTrailing" destination="YNn-8w-SmG" id="lL1-5q-mjx"/>
</connections>
<point key="canvasLocation" x="383" y="54"/>
</collectionViewCell>
</objects>
</document>

View file

@ -503,10 +503,16 @@ void logPointEvent(MWMRoutePoint * point, NSString * eventType)
{
if (![MWMRouter isRoutingActive])
return;
auto const & rm = GetFramework().GetRoutingManager();
location::FollowingInfo info;
GetFramework().GetRoutingManager().GetRouteFollowingInfo(info);
if (info.IsValid())
[[MWMNavigationDashboardManager manager] updateFollowingInfo:info];
rm.GetRouteFollowingInfo(info);
auto navManager = [MWMNavigationDashboardManager manager];
if (!info.IsValid())
return;
if ([MWMRouter type] == MWMRouterTypePublicTransport)
[navManager updateTransitInfo:rm.GetTransitRouteInfo()];
else
[navManager updateFollowingInfo:info];
}
+ (void)routeAltitudeImageForSize:(CGSize)size completion:(MWMImageHeightBlock)block

View file

@ -0,0 +1,12 @@
#import "MWMRouterTransitType.h"
@interface MWMRouterTransitStepInfo : NSObject
@property(nonatomic, readonly) MWMRouterTransitType type;
@property(copy, nonatomic, readonly) NSString * distance;
@property(copy, nonatomic, readonly) NSString * distanceUnits;
@property(copy, nonatomic, readonly) NSString * number;
@property(nonatomic, readonly) UIColor * color;
@property(nonatomic, readonly) NSInteger intermediateIndex;
@end

View file

@ -0,0 +1,58 @@
#import "MWMRouterTransitStepInfo.h"
#include "map/routing_manager.hpp"
namespace
{
MWMRouterTransitType convertType(TransitType type)
{
switch (type)
{
case TransitType::IntermediatePoint: return MWMRouterTransitTypeIntermediatePoint;
case TransitType::Pedestrian: return MWMRouterTransitTypePedestrian;
case TransitType::Subway: return MWMRouterTransitTypeSubway;
case TransitType::Train: return MWMRouterTransitTypeTrain;
case TransitType::LightRail: return MWMRouterTransitTypeLightRail;
case TransitType::Monorail: return MWMRouterTransitTypeMonorail;
}
}
UIColor * convertColor(uint32_t colorARGB)
{
CGFloat const alpha = CGFloat((colorARGB >> 24) & 0xFF) / 255;
CGFloat const red = CGFloat((colorARGB >> 16) & 0xFF) / 255;
CGFloat const green = CGFloat((colorARGB >> 8) & 0xFF) / 255;
CGFloat const blue = CGFloat(colorARGB & 0xFF) / 255;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
} // namespace
@interface MWMRouterTransitStepInfo ()
@property(nonatomic, readwrite) MWMRouterTransitType type;
@property(copy, nonatomic, readwrite) NSString * distance;
@property(copy, nonatomic, readwrite) NSString * distanceUnits;
@property(copy, nonatomic, readwrite) NSString * number;
@property(nonatomic, readwrite) UIColor * color;
@property(nonatomic, readwrite) NSInteger intermediateIndex;
@end
@implementation MWMRouterTransitStepInfo
- (instancetype)initWithStepInfo:(TransitStepInfo const &)info
{
self = [super init];
if (self)
{
_type = convertType(info.m_type);
_distance = @(info.m_distanceStr.c_str());
_distanceUnits = @(info.m_distanceUnitsSuffix.c_str());
_number = @(info.m_number.c_str());
_color = convertColor(info.m_colorARGB);
_intermediateIndex = info.m_intermediateIndex;
}
return self;
}
@end

View file

@ -0,0 +1,8 @@
typedef NS_ENUM(NSUInteger, MWMRouterTransitType) {
MWMRouterTransitTypeIntermediatePoint,
MWMRouterTransitTypePedestrian,
MWMRouterTransitTypeSubway,
MWMRouterTransitTypeTrain,
MWMRouterTransitTypeLightRail,
MWMRouterTransitTypeMonorail
};

File diff suppressed because it is too large Load diff