Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
11
iphone/Maps/UI/BottomMenu/MWMBottomMenuState.h
Normal file
11
iphone/Maps/UI/BottomMenu/MWMBottomMenuState.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef MWMBottomMenuState_h
|
||||
#define MWMBottomMenuState_h
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MWMBottomMenuState) {
|
||||
MWMBottomMenuStateHidden,
|
||||
MWMBottomMenuStateInactive,
|
||||
MWMBottomMenuStateActive,
|
||||
MWMBottomMenuStateLayers
|
||||
};
|
||||
|
||||
#endif /* MWMBottomMenuState_h */
|
||||
36
iphone/Maps/UI/BottomMenu/Menu/BottomMenuBuilder.swift
Normal file
36
iphone/Maps/UI/BottomMenu/Menu/BottomMenuBuilder.swift
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
@objc class BottomMenuBuilder: NSObject {
|
||||
@objc static func buildMenu(mapViewController: MapViewController,
|
||||
controlsManager: MWMMapViewControlsManager,
|
||||
delegate: BottomMenuDelegate) -> UIViewController {
|
||||
return BottomMenuBuilder.build(mapViewController: mapViewController,
|
||||
controlsManager: controlsManager,
|
||||
delegate: delegate,
|
||||
sections: [.layers, .items])
|
||||
}
|
||||
|
||||
@objc static func buildLayers(mapViewController: MapViewController,
|
||||
controlsManager: MWMMapViewControlsManager,
|
||||
delegate: BottomMenuDelegate) -> UIViewController {
|
||||
return BottomMenuBuilder.build(mapViewController: mapViewController,
|
||||
controlsManager: controlsManager,
|
||||
delegate: delegate,
|
||||
sections: [.layers])
|
||||
}
|
||||
|
||||
private static func build(mapViewController: MapViewController,
|
||||
controlsManager: MWMMapViewControlsManager,
|
||||
delegate: BottomMenuDelegate,
|
||||
sections: [BottomMenuPresenter.Sections]) -> UIViewController {
|
||||
let viewController = BottomMenuViewController(nibName: nil, bundle: nil)
|
||||
let interactor = BottomMenuInteractor(viewController: viewController,
|
||||
mapViewController: mapViewController,
|
||||
controlsManager: controlsManager,
|
||||
delegate: delegate)
|
||||
let presenter = BottomMenuPresenter(view: viewController, interactor: interactor, sections: sections)
|
||||
|
||||
interactor.presenter = presenter
|
||||
viewController.presenter = presenter
|
||||
|
||||
return viewController
|
||||
}
|
||||
}
|
||||
101
iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift
Normal file
101
iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
protocol BottomMenuInteractorProtocol: AnyObject {
|
||||
func close()
|
||||
func addPlace()
|
||||
func downloadMaps()
|
||||
func donate()
|
||||
func openHelp()
|
||||
func openSettings()
|
||||
func shareLocation(cell: BottomMenuItemCell)
|
||||
func toggleTrackRecording()
|
||||
}
|
||||
|
||||
@objc protocol BottomMenuDelegate {
|
||||
func actionDownloadMaps(_ mode: MWMMapDownloaderMode)
|
||||
func addPlace()
|
||||
func didFinishAddingPlace()
|
||||
}
|
||||
|
||||
class BottomMenuInteractor {
|
||||
weak var presenter: BottomMenuPresenterProtocol?
|
||||
private weak var viewController: UIViewController?
|
||||
private weak var mapViewController: MapViewController?
|
||||
private weak var delegate: BottomMenuDelegate?
|
||||
private weak var controlsManager: MWMMapViewControlsManager?
|
||||
|
||||
private let trackRecorder: TrackRecordingManager = .shared
|
||||
|
||||
init(viewController: UIViewController,
|
||||
mapViewController: MapViewController,
|
||||
controlsManager: MWMMapViewControlsManager,
|
||||
delegate: BottomMenuDelegate) {
|
||||
self.viewController = viewController
|
||||
self.mapViewController = mapViewController
|
||||
self.delegate = delegate
|
||||
self.controlsManager = controlsManager
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomMenuInteractor: BottomMenuInteractorProtocol {
|
||||
func close() {
|
||||
guard let controlsManager = controlsManager else {
|
||||
fatalError()
|
||||
}
|
||||
controlsManager.menuState = controlsManager.menuRestoreState
|
||||
}
|
||||
|
||||
func addPlace() {
|
||||
delegate?.addPlace()
|
||||
}
|
||||
|
||||
func donate() {
|
||||
close()
|
||||
guard var url = SettingsBridge.donateUrl() else { return }
|
||||
if url == "https://www.comaps.app/donate/" {
|
||||
url = L("translated_om_site_url") + "donate/"
|
||||
}
|
||||
viewController?.openUrl(url, externally: true)
|
||||
}
|
||||
|
||||
func downloadMaps() {
|
||||
close()
|
||||
delegate?.actionDownloadMaps(.downloaded)
|
||||
}
|
||||
|
||||
func openHelp() {
|
||||
close()
|
||||
mapViewController?.openAbout()
|
||||
}
|
||||
|
||||
func openSettings() {
|
||||
close()
|
||||
mapViewController?.openSettings()
|
||||
}
|
||||
|
||||
func shareLocation(cell: BottomMenuItemCell) {
|
||||
guard let coordinates = LocationManager.lastLocation()?.coordinate else {
|
||||
viewController?.present(UIAlertController.unknownCurrentPosition(), animated: true, completion: nil)
|
||||
return
|
||||
}
|
||||
guard let viewController = viewController else { return }
|
||||
let vc = ActivityViewController.share(forMyPosition: coordinates)
|
||||
vc.present(inParentViewController: viewController, anchorView: cell.anchorView)
|
||||
}
|
||||
|
||||
func toggleTrackRecording() {
|
||||
close()
|
||||
let mapViewController = MapViewController.shared()!
|
||||
switch trackRecorder.recordingState {
|
||||
case .active:
|
||||
mapViewController.showTrackRecordingPlacePage()
|
||||
case .inactive:
|
||||
trackRecorder.start { result in
|
||||
switch result {
|
||||
case .success:
|
||||
mapViewController.showTrackRecordingPlacePage()
|
||||
case .failure:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
178
iphone/Maps/UI/BottomMenu/Menu/BottomMenuPresenter.swift
Normal file
178
iphone/Maps/UI/BottomMenu/Menu/BottomMenuPresenter.swift
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
protocol BottomMenuPresenterProtocol: UITableViewDelegate, UITableViewDataSource {
|
||||
func onClosePressed()
|
||||
func cellToHighlightIndexPath() -> IndexPath?
|
||||
func setCellHighlighted(_ highlighted: Bool)
|
||||
}
|
||||
|
||||
class BottomMenuPresenter: NSObject {
|
||||
enum CellType: Int, CaseIterable {
|
||||
case addPlace
|
||||
case recordTrack
|
||||
case share
|
||||
case donate
|
||||
case downloadMaps
|
||||
case settings
|
||||
case help
|
||||
}
|
||||
|
||||
enum Sections: Int {
|
||||
case layers
|
||||
case items
|
||||
}
|
||||
|
||||
private weak var view: BottomMenuViewProtocol?
|
||||
private let interactor: BottomMenuInteractorProtocol
|
||||
private let sections: [Sections]
|
||||
private var menuCells: [CellType]
|
||||
private let trackRecorder = TrackRecordingManager.shared
|
||||
private var cellToHighlight: CellType?
|
||||
|
||||
init(view: BottomMenuViewProtocol,
|
||||
interactor: BottomMenuInteractorProtocol,
|
||||
sections: [Sections]) {
|
||||
self.view = view
|
||||
self.interactor = interactor
|
||||
self.sections = sections
|
||||
self.menuCells = []
|
||||
self.cellToHighlight = Self.getCellToHighlight()
|
||||
super.init()
|
||||
}
|
||||
|
||||
private static func getCellToHighlight() -> CellType? {
|
||||
let featureToHighlightData = DeepLinkHandler.shared.getInAppFeatureHighlightData()
|
||||
guard let featureToHighlightData, featureToHighlightData.urlType == .menu else { return nil }
|
||||
switch featureToHighlightData.feature {
|
||||
case .trackRecorder: return .recordTrack
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomMenuPresenter: BottomMenuPresenterProtocol {
|
||||
func onClosePressed() {
|
||||
interactor.close()
|
||||
}
|
||||
|
||||
func cellToHighlightIndexPath() -> IndexPath? {
|
||||
// Highlighting is enabled only for the .items section.
|
||||
guard let cellToHighlight,
|
||||
let sectionIndex = sections.firstIndex(of: .items),
|
||||
let cellIndex = menuCells.firstIndex(of: cellToHighlight) else { return nil }
|
||||
return IndexPath(row: cellIndex, section: sectionIndex)
|
||||
}
|
||||
|
||||
func setCellHighlighted(_ highlighted: Bool) {
|
||||
cellToHighlight = nil
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -- UITableViewDataSource
|
||||
|
||||
extension BottomMenuPresenter {
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
sections.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
switch sections[section] {
|
||||
case .layers:
|
||||
return 1
|
||||
case .items:
|
||||
let leftButtonType = Settings.leftButtonType
|
||||
menuCells = CellType.allCases.filter { cell in
|
||||
if cell == .donate {
|
||||
return false
|
||||
} else if leftButtonType == .addPlace, cell == .addPlace {
|
||||
return false
|
||||
} else if leftButtonType == .recordTrack, cell == .recordTrack {
|
||||
return false
|
||||
} else if leftButtonType == .help, cell == .help {
|
||||
return false
|
||||
} else if leftButtonType == .settings, cell == .settings {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return menuCells.count
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
switch sections[indexPath.section] {
|
||||
case .layers:
|
||||
let cell = tableView.dequeueReusableCell(cell: BottomMenuLayersCell.self)!
|
||||
cell.onClose = { [weak self] in self?.onClosePressed() }
|
||||
if sections.count > 1 {
|
||||
cell.addSeparator(.bottom)
|
||||
}
|
||||
return cell
|
||||
case .items:
|
||||
let cell = tableView.dequeueReusableCell(cell: BottomMenuItemCell.self)!
|
||||
switch menuCells[indexPath.row] {
|
||||
case .addPlace:
|
||||
let enabled = MWMNavigationDashboardManager.shared().state == .hidden && FrameworkHelper.canEditMapAtViewportCenter()
|
||||
cell.configure(imageName: "plus",
|
||||
title: L("placepage_add_place_button"),
|
||||
enabled: enabled)
|
||||
case .recordTrack:
|
||||
cell.configure(imageName: "track", title: L("start_track_recording"))
|
||||
case .downloadMaps:
|
||||
cell.configure(imageName: "ic_menu_download",
|
||||
title: L("download_maps"),
|
||||
badgeCount: MapsAppDelegate.theApp().badgeNumber())
|
||||
case .donate:
|
||||
cell.configure(imageName: "ic_menu_donate",
|
||||
title: L("donate"))
|
||||
case .help:
|
||||
cell.configure(imageName: "help",
|
||||
title: L("help"))
|
||||
case .settings:
|
||||
cell.configure(imageName: "gearshape.fill",
|
||||
title: L("settings"))
|
||||
case .share:
|
||||
cell.configure(imageName: "square.and.arrow.up",
|
||||
title: L("share_my_location"))
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -- UITableViewDelegate
|
||||
|
||||
extension BottomMenuPresenter {
|
||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if let cell = tableView.cellForRow(at: indexPath) as? BottomMenuItemCell {
|
||||
return cell.isEnabled ? indexPath : nil
|
||||
}
|
||||
return indexPath
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
switch sections[indexPath.section] {
|
||||
case .layers:
|
||||
return;
|
||||
case .items:
|
||||
switch menuCells[indexPath.row] {
|
||||
case .addPlace:
|
||||
interactor.addPlace()
|
||||
case .recordTrack:
|
||||
interactor.toggleTrackRecording()
|
||||
case .downloadMaps:
|
||||
interactor.downloadMaps()
|
||||
case .donate:
|
||||
interactor.donate()
|
||||
case .help:
|
||||
interactor.openHelp()
|
||||
case .settings:
|
||||
interactor.openSettings()
|
||||
case .share:
|
||||
if let cell = tableView.cellForRow(at: indexPath) as? BottomMenuItemCell {
|
||||
interactor.shareLocation(cell: cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
iphone/Maps/UI/BottomMenu/Menu/BottomMenuViewController.swift
Normal file
100
iphone/Maps/UI/BottomMenu/Menu/BottomMenuViewController.swift
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
protocol BottomMenuViewProtocol: AnyObject {
|
||||
var presenter: BottomMenuPresenterProtocol? { get set }
|
||||
}
|
||||
|
||||
class BottomMenuViewController: MWMViewController {
|
||||
var presenter: BottomMenuPresenterProtocol?
|
||||
private let transitioningManager = BottomMenuTransitioningManager()
|
||||
|
||||
@IBOutlet var tableView: UITableView!
|
||||
@IBOutlet var heightConstraint: NSLayoutConstraint!
|
||||
@IBOutlet var bottomConstraint: NSLayoutConstraint!
|
||||
|
||||
lazy var chromeView: UIView = {
|
||||
let view = UIView()
|
||||
view.setStyle(.presentationBackground)
|
||||
return view
|
||||
}()
|
||||
|
||||
weak var containerView: UIView! {
|
||||
didSet {
|
||||
containerView.insertSubview(chromeView, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
tableView.layer.setCornerRadius(.buttonDefault, maskedCorners: [.layerMinXMinYCorner, .layerMaxXMinYCorner])
|
||||
tableView.sectionFooterHeight = 0
|
||||
|
||||
tableView.dataSource = presenter
|
||||
tableView.delegate = presenter
|
||||
tableView.registerNib(cell: BottomMenuItemCell.self)
|
||||
tableView.registerNib(cell: BottomMenuLayersCell.self)
|
||||
|
||||
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: nil) { _ in
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if let cellToHighlight = presenter?.cellToHighlightIndexPath() {
|
||||
tableView.cellForRow(at: cellToHighlight)?.highlight()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
tableView.setNeedsLayout()
|
||||
tableView.layoutIfNeeded()
|
||||
heightConstraint.constant = min(tableView.contentSize.height, view.height)
|
||||
tableView.isScrollEnabled = tableView.contentSize.height > heightConstraint.constant;
|
||||
}
|
||||
|
||||
@IBAction func onClosePressed(_ sender: Any) {
|
||||
presenter?.onClosePressed()
|
||||
}
|
||||
|
||||
@IBAction func onPan(_ sender: UIPanGestureRecognizer) {
|
||||
let yOffset = sender.translation(in: view.superview).y
|
||||
let yVelocity = sender.velocity(in: view.superview).y
|
||||
sender.setTranslation(CGPoint.zero, in: view.superview)
|
||||
bottomConstraint.constant = min(bottomConstraint.constant - yOffset, 0);
|
||||
|
||||
let alpha = 1.0 - abs(bottomConstraint.constant / tableView.height)
|
||||
self.chromeView.alpha = alpha
|
||||
|
||||
let state = sender.state
|
||||
if state == .ended || state == .cancelled {
|
||||
if yVelocity > 0 || (yVelocity == 0 && alpha < 0.8) {
|
||||
presenter?.onClosePressed()
|
||||
} else {
|
||||
let duration = min(kDefaultAnimationDuration, TimeInterval(self.bottomConstraint.constant / yVelocity))
|
||||
self.view.layoutIfNeeded()
|
||||
UIView.animate(withDuration: duration) {
|
||||
self.chromeView.alpha = 1
|
||||
self.bottomConstraint.constant = 0
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var transitioningDelegate: UIViewControllerTransitioningDelegate? {
|
||||
get { return transitioningManager }
|
||||
set { }
|
||||
}
|
||||
|
||||
override var modalPresentationStyle: UIModalPresentationStyle {
|
||||
get { return .custom }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomMenuViewController: BottomMenuViewProtocol {
|
||||
|
||||
}
|
||||
95
iphone/Maps/UI/BottomMenu/Menu/BottomMenuViewController.xib
Normal file
95
iphone/Maps/UI/BottomMenu/Menu/BottomMenuViewController.xib
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
|
||||
<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="BottomMenuViewController" customModule="CoMaps" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="bottomConstraint" destination="Crm-Ym-Ikk" id="K0d-Ad-Q13"/>
|
||||
<outlet property="heightConstraint" destination="dYV-fi-iGj" id="chn-o3-rhF"/>
|
||||
<outlet property="tableView" destination="L4F-0e-1B7" id="dHQ-DU-QPO"/>
|
||||
<outlet property="view" destination="iN0-l3-epB" id="nOL-DH-swt"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DD7-rW-ckP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="862"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="sXH-Kv-ZnQ" appends="YES" id="u82-AO-mZ1"/>
|
||||
</connections>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="L4F-0e-1B7">
|
||||
<rect key="frame" x="0.0" y="562" width="414" height="300"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="350" id="Jyo-UJ-ltJ"/>
|
||||
<constraint firstAttribute="height" priority="750" constant="300" id="dYV-fi-iGj"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="Jyo-UJ-ltJ"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="Jyo-UJ-ltJ"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M4g-vy-YtE" userLabel="Bottom View">
|
||||
<rect key="frame" x="0.0" y="862" width="414" height="34"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Background"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="L4F-0e-1B7" secondAttribute="bottom" id="Crm-Ym-Ikk"/>
|
||||
<constraint firstItem="M4g-vy-YtE" firstAttribute="top" secondItem="L4F-0e-1B7" secondAttribute="bottom" id="E7M-j3-lrN"/>
|
||||
<constraint firstItem="DD7-rW-ckP" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="LOj-yu-5nE"/>
|
||||
<constraint firstItem="M4g-vy-YtE" firstAttribute="trailing" secondItem="L4F-0e-1B7" secondAttribute="trailing" id="PdB-CC-VOI"/>
|
||||
<constraint firstItem="DD7-rW-ckP" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Vxc-mf-jVJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="DD7-rW-ckP" secondAttribute="trailing" id="WAo-c4-geW"/>
|
||||
<constraint firstItem="M4g-vy-YtE" firstAttribute="leading" secondItem="L4F-0e-1B7" secondAttribute="leading" id="cjE-84-gfc"/>
|
||||
<constraint firstItem="DD7-rW-ckP" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="deF-nX-Ae5"/>
|
||||
<constraint firstItem="L4F-0e-1B7" firstAttribute="top" relation="greaterThanOrEqual" secondItem="iN0-l3-epB" secondAttribute="top" id="fDu-HA-dhq"/>
|
||||
<constraint firstItem="L4F-0e-1B7" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="g7h-Yh-azG"/>
|
||||
<constraint firstAttribute="bottom" secondItem="M4g-vy-YtE" secondAttribute="bottom" priority="750" id="hFA-7p-XKe"/>
|
||||
<constraint firstItem="L4F-0e-1B7" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="t8e-ZM-EdJ"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<variation key="heightClass=compact">
|
||||
<mask key="constraints">
|
||||
<exclude reference="g7h-Yh-azG"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<connections>
|
||||
<outletCollection property="gestureRecognizers" destination="Rdk-jI-mZR" appends="YES" id="bbV-GO-4iF"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="137.68115942028987" y="153.34821428571428"/>
|
||||
</view>
|
||||
<tapGestureRecognizer cancelsTouchesInView="NO" id="sXH-Kv-ZnQ">
|
||||
<connections>
|
||||
<action selector="onClosePressed:" destination="-1" id="nMr-L4-IGY"/>
|
||||
</connections>
|
||||
</tapGestureRecognizer>
|
||||
<panGestureRecognizer delaysTouchesBegan="YES" delaysTouchesEnded="NO" minimumNumberOfTouches="1" id="Rdk-jI-mZR">
|
||||
<connections>
|
||||
<action selector="onPan:" destination="-1" id="yGW-xa-dnH"/>
|
||||
</connections>
|
||||
</panGestureRecognizer>
|
||||
</objects>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import UIKit
|
||||
|
||||
class BottomMenuItemCell: UITableViewCell {
|
||||
@IBOutlet private var label: UILabel!
|
||||
@IBOutlet private var badgeBackground: UIView!
|
||||
@IBOutlet private var badgeCountLabel: UILabel!
|
||||
@IBOutlet private var separator: UIView!
|
||||
@IBOutlet private var icon: UIImageView!
|
||||
@IBOutlet private var badgeSpacingConstraint: NSLayoutConstraint!
|
||||
@IBOutlet private var badgeBackgroundWidthConstraint: NSLayoutConstraint!
|
||||
var anchorView: UIView {
|
||||
get {
|
||||
return icon
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var isEnabled: Bool = true
|
||||
|
||||
func configure(imageName: String, title: String, badgeCount: UInt = .zero, enabled: Bool = true) {
|
||||
if imageName == "help" {
|
||||
icon.image = Settings.LeftButtonType.help.image
|
||||
} else if imageName == "plus" {
|
||||
icon.image = Settings.LeftButtonType.addPlace.image
|
||||
} else if imageName == "track" {
|
||||
icon.image = Settings.LeftButtonType.recordTrack.image
|
||||
} else if imageName == "ic_menu_download" || imageName == "ic_menu_donate" {
|
||||
icon.image = UIImage(named: imageName)
|
||||
} else {
|
||||
let configuration = UIImage.SymbolConfiguration(pointSize: 22, weight: .semibold)
|
||||
icon.image = UIImage(systemName: imageName, withConfiguration: configuration)!
|
||||
}
|
||||
|
||||
label.text = title
|
||||
badgeBackground.isHidden = badgeCount == 0
|
||||
badgeCountLabel.text = "\(badgeCount)"
|
||||
if badgeCount == 0 {
|
||||
badgeSpacingConstraint.constant = 0
|
||||
badgeBackgroundWidthConstraint.constant = 0
|
||||
} else {
|
||||
badgeSpacingConstraint.constant = 8
|
||||
badgeBackgroundWidthConstraint.constant = 32
|
||||
}
|
||||
isEnabled = enabled
|
||||
icon.setStyleAndApply(isEnabled ? .black : .gray)
|
||||
label.setFontStyleAndApply(isEnabled ? .blackPrimary : .blackHint)
|
||||
}
|
||||
}
|
||||
107
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuItemCell.xib
Normal file
107
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuItemCell.xib
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
|
||||
<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"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="48" id="gZi-cd-LgO" customClass="BottomMenuItemCell" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="gZi-cd-LgO" id="rsu-1s-Lsp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_menu_download" translatesAutoresizingMaskIntoConstraints="NO" id="8oJ-8z-qRL">
|
||||
<rect key="frame" x="16" y="10" width="28" height="28"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="28" id="Hth-JK-nv2"/>
|
||||
<constraint firstAttribute="height" constant="28" id="zil-Ys-XYB"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="MWMBlack"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Uc-o1-PsF">
|
||||
<rect key="frame" x="60" y="14" width="298" height="20"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="regular16:blackPrimaryText"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="con-tP-3dJ" userLabel="DownloadBadgeBackground">
|
||||
<rect key="frame" x="366" y="14" width="32" height="20"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FT9-8n-RZm" userLabel="DownloadBadgeCount">
|
||||
<rect key="frame" x="0.0" y="0.0" width="32" height="20"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="FT9-8n-RZm" secondAttribute="trailing" id="Ge3-P2-idS"/>
|
||||
<constraint firstAttribute="bottom" secondItem="FT9-8n-RZm" secondAttribute="bottom" id="Kgn-y3-dBT"/>
|
||||
<constraint firstItem="FT9-8n-RZm" firstAttribute="top" secondItem="con-tP-3dJ" secondAttribute="top" id="LaN-Vb-w2N"/>
|
||||
<constraint firstAttribute="height" constant="20" id="Y5v-7h-SGf"/>
|
||||
<constraint firstItem="FT9-8n-RZm" firstAttribute="leading" secondItem="con-tP-3dJ" secondAttribute="leading" id="pE4-Qs-ctY"/>
|
||||
<constraint firstAttribute="width" constant="32" id="ubK-0L-pDn"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Badge"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4OJ-wN-dY4" userLabel="Separator">
|
||||
<rect key="frame" x="60" y="47" width="354" height="1"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="tDM-AP-ern"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Divider"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5Uc-o1-PsF" firstAttribute="leading" secondItem="4OJ-wN-dY4" secondAttribute="leading" id="9g1-Uo-zCa"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8oJ-8z-qRL" secondAttribute="bottom" constant="10" id="KJP-IG-4FK"/>
|
||||
<constraint firstItem="FT9-8n-RZm" firstAttribute="leading" secondItem="5Uc-o1-PsF" secondAttribute="trailing" constant="8" id="RJA-NS-MXP"/>
|
||||
<constraint firstItem="8oJ-8z-qRL" firstAttribute="top" secondItem="rsu-1s-Lsp" secondAttribute="top" constant="10" id="bab-2f-YZY"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="4OJ-wN-dY4" secondAttribute="trailing" id="3Vq-qn-yhm"/>
|
||||
<constraint firstItem="4OJ-wN-dY4" firstAttribute="leading" secondItem="gZi-cd-LgO" secondAttribute="leading" constant="60" id="7wy-Q8-lja"/>
|
||||
<constraint firstAttribute="trailing" secondItem="con-tP-3dJ" secondAttribute="trailing" constant="16" id="Bm7-vh-vYz"/>
|
||||
<constraint firstItem="8oJ-8z-qRL" firstAttribute="leading" secondItem="gZi-cd-LgO" secondAttribute="leading" constant="16" id="I7K-bz-QOC"/>
|
||||
<constraint firstAttribute="bottom" secondItem="4OJ-wN-dY4" secondAttribute="bottom" id="SVQ-VP-J4d"/>
|
||||
<constraint firstItem="con-tP-3dJ" firstAttribute="centerY" secondItem="gZi-cd-LgO" secondAttribute="centerY" id="UY4-uw-Kda"/>
|
||||
<constraint firstItem="5Uc-o1-PsF" firstAttribute="centerY" secondItem="gZi-cd-LgO" secondAttribute="centerY" id="hVt-zE-3iE"/>
|
||||
<constraint firstItem="8oJ-8z-qRL" firstAttribute="centerY" secondItem="gZi-cd-LgO" secondAttribute="centerY" id="u2b-9I-SLh"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="badgeBackground" destination="con-tP-3dJ" id="vH5-Rd-uqS"/>
|
||||
<outlet property="badgeBackgroundWidthConstraint" destination="ubK-0L-pDn" id="D3B-sV-eGO"/>
|
||||
<outlet property="badgeCountLabel" destination="FT9-8n-RZm" id="HLY-2S-do9"/>
|
||||
<outlet property="badgeSpacingConstraint" destination="RJA-NS-MXP" id="Hpf-eq-1C1"/>
|
||||
<outlet property="icon" destination="8oJ-8z-qRL" id="qcD-Kv-c5l"/>
|
||||
<outlet property="label" destination="5Uc-o1-PsF" id="y4l-b6-MCt"/>
|
||||
<outlet property="separator" destination="4OJ-wN-dY4" id="Kkv-HO-0eK"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="337.68115942028987" y="527.00892857142856"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="ic_menu_download" width="28" height="28"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
final class BottomMenuLayerButton: VerticallyAlignedButton {
|
||||
private var badgeView: UIView?
|
||||
private let badgeSize = CGSize(width: 12, height: 12)
|
||||
private let badgeOffset = CGPoint(x: -3, y: 3)
|
||||
|
||||
var isBadgeHidden: Bool = true{
|
||||
didSet {
|
||||
if oldValue != isBadgeHidden {
|
||||
updateBadge()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
imageView.layer.masksToBounds = true
|
||||
updateBadge()
|
||||
}
|
||||
|
||||
private func updateBadge() {
|
||||
if isBadgeHidden {
|
||||
badgeView?.removeFromSuperview()
|
||||
badgeView = nil
|
||||
} else {
|
||||
if badgeView == nil {
|
||||
badgeView = UIView()
|
||||
badgeView?.setStyle(.badge)
|
||||
addSubview(badgeView!)
|
||||
}
|
||||
let imageFrame = imageView.frame
|
||||
badgeView?.frame = CGRect(x:imageFrame.minX + imageFrame.width - badgeSize.width / 2 + badgeOffset.x,
|
||||
y:imageFrame.minY - badgeSize.height/2 + badgeOffset.y,
|
||||
width: badgeSize.width,
|
||||
height: badgeSize.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
107
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuLayersCell.swift
Normal file
107
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuLayersCell.swift
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import UIKit
|
||||
|
||||
class BottomMenuLayersCell: UITableViewCell {
|
||||
@IBOutlet weak var closeButton: CircleImageButton!
|
||||
|
||||
@IBOutlet private var subwayButton: BottomMenuLayerButton! {
|
||||
didSet {
|
||||
updateSubwayButton()
|
||||
}
|
||||
}
|
||||
@IBOutlet private var isoLinesButton: BottomMenuLayerButton! {
|
||||
didSet {
|
||||
updateIsoLinesButton()
|
||||
}
|
||||
}
|
||||
@IBOutlet private var outdoorButton: BottomMenuLayerButton! {
|
||||
didSet {
|
||||
updateOutdoorButton()
|
||||
}
|
||||
}
|
||||
|
||||
var onClose: (()->())?
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
MapOverlayManager.add(self)
|
||||
closeButton.setImage(UIImage(named: "ic_close"))
|
||||
setupButtons()
|
||||
}
|
||||
|
||||
private func setupButtons() {
|
||||
outdoorButton.setupWith(image: UIImage(resource: .btnMenuOutdoors), text: L("button_layer_outdoor"))
|
||||
isoLinesButton.setupWith(image: UIImage(resource: .btnMenuIsomaps), text: L("button_layer_isolines"))
|
||||
subwayButton.setupWith(image: UIImage(resource: .btnMenuSubway), text: L("button_layer_subway"))
|
||||
}
|
||||
|
||||
deinit {
|
||||
MapOverlayManager.remove(self)
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
}
|
||||
|
||||
private func updateSubwayButton() {
|
||||
let enabled = MapOverlayManager.transitEnabled()
|
||||
subwayButton.setStyleAndApply(styleFor(enabled))
|
||||
}
|
||||
|
||||
private func updateIsoLinesButton() {
|
||||
let enabled = MapOverlayManager.isoLinesEnabled()
|
||||
isoLinesButton.setStyleAndApply(styleFor(enabled))
|
||||
}
|
||||
|
||||
private func updateOutdoorButton() {
|
||||
let enabled = MapOverlayManager.outdoorEnabled()
|
||||
outdoorButton.setStyleAndApply(styleFor(enabled))
|
||||
}
|
||||
|
||||
@IBAction func onCloseButtonPressed(_ sender: Any) {
|
||||
onClose?()
|
||||
}
|
||||
|
||||
@IBAction func onSubwayButton(_ sender: Any) {
|
||||
let enable = !MapOverlayManager.transitEnabled()
|
||||
MapOverlayManager.setTransitEnabled(enable)
|
||||
}
|
||||
|
||||
@IBAction func onIsoLinesButton(_ sender: Any) {
|
||||
let enable = !MapOverlayManager.isoLinesEnabled()
|
||||
MapOverlayManager.setIsoLinesEnabled(enable)
|
||||
}
|
||||
|
||||
@IBAction func onOutdoorButton(_ sender: Any) {
|
||||
let enable = !MapOverlayManager.outdoorEnabled()
|
||||
MapOverlayManager.setOutdoorEnabled(enable)
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomMenuLayersCell: MapOverlayManagerObserver {
|
||||
func onTransitStateUpdated() {
|
||||
updateSubwayButton()
|
||||
}
|
||||
|
||||
func onIsoLinesStateUpdated() {
|
||||
updateIsoLinesButton()
|
||||
}
|
||||
|
||||
func onOutdoorStateUpdated() {
|
||||
updateOutdoorButton()
|
||||
}
|
||||
}
|
||||
|
||||
private extension BottomMenuLayersCell {
|
||||
func styleFor(_ enabled: Bool) -> MapStyleSheet {
|
||||
enabled ? .mapMenuButtonEnabled : .mapMenuButtonDisabled
|
||||
}
|
||||
}
|
||||
|
||||
private extension BottomMenuLayerButton {
|
||||
func setupWith(image: UIImage, text: String) {
|
||||
self.image = image
|
||||
spacing = 10
|
||||
numberOfLines = 2
|
||||
localizedText = text
|
||||
}
|
||||
}
|
||||
151
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuLayersCell.xib
Normal file
151
iphone/Maps/UI/BottomMenu/Menu/Cells/BottomMenuLayersCell.xib
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="ipad9_7" orientation="landscape" layout="fullscreen" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<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"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="165" id="KGk-i7-Jjw" customClass="BottomMenuLayersCell" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="340" height="165"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="340" height="165"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W1i-v6-zbz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="340" height="50"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Map Layers" textAlignment="natural" lineBreakMode="clip" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vuk-dn-n2c">
|
||||
<rect key="frame" x="119.5" y="13" width="101.5" height="24"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="blackPrimaryText:bold22"/>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="layers_title"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2xW-dK-D9y" customClass="CircleImageButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="296" y="11" width="28" height="28"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="28" id="BD2-bz-n13"/>
|
||||
<constraint firstAttribute="width" constant="28" id="Thu-MY-dQm"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="onCloseButtonPressed:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="8vd-Pg-Suh"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="00h-1i-skR"/>
|
||||
<constraint firstItem="2xW-dK-D9y" firstAttribute="leading" secondItem="Vuk-dn-n2c" secondAttribute="trailing" constant="8" id="4PG-Fm-yqS"/>
|
||||
<constraint firstItem="Vuk-dn-n2c" firstAttribute="centerY" secondItem="W1i-v6-zbz" secondAttribute="centerY" id="4du-pr-7hv"/>
|
||||
<constraint firstAttribute="height" constant="45" id="Ez1-s5-1EO"/>
|
||||
<constraint firstItem="Vuk-dn-n2c" firstAttribute="centerX" secondItem="W1i-v6-zbz" secondAttribute="centerX" id="XEG-CK-41Y"/>
|
||||
<constraint firstItem="Vuk-dn-n2c" firstAttribute="leading" secondItem="W1i-v6-zbz" secondAttribute="leading" constant="16" id="kSJ-Wa-nYA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="2xW-dK-D9y" secondAttribute="trailing" constant="16" id="kae-50-2nG"/>
|
||||
<constraint firstItem="2xW-dK-D9y" firstAttribute="centerY" secondItem="Vuk-dn-n2c" secondAttribute="centerY" id="wCu-O0-cz8"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="00h-1i-skR"/>
|
||||
<exclude reference="Ez1-s5-1EO"/>
|
||||
<exclude reference="XEG-CK-41Y"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="Ez1-s5-1EO"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="00h-1i-skR"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular-widthClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="XEG-CK-41Y"/>
|
||||
<exclude reference="kSJ-Wa-nYA"/>
|
||||
<exclude reference="4PG-Fm-yqS"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="sRd-zd-xSl">
|
||||
<rect key="frame" x="16" y="58" width="308" height="64"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g13-pK-Eig" userLabel="Outdoor Button" customClass="BottomMenuLayerButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="102.5" height="64"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="onOutdoorButton:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="UQ2-jj-fPc"/>
|
||||
</connections>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="edA-Mo-3Vx" customClass="BottomMenuLayerButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="102.5" y="0.0" width="103" height="64"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="onIsoLinesButton:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="3LS-C2-2Mc"/>
|
||||
</connections>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4US-fZ-cyg" customClass="BottomMenuLayerButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="205.5" y="0.0" width="102.5" height="64"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<action selector="onSubwayButton:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="xxM-kP-gT1"/>
|
||||
</connections>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="70" id="d0H-kE-IWx"/>
|
||||
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="nea-IB-ZkL"/>
|
||||
<constraint firstAttribute="height" constant="64" id="t9j-kf-yze"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="d0H-kE-IWx"/>
|
||||
<exclude reference="t9j-kf-yze"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=compact">
|
||||
<mask key="constraints">
|
||||
<include reference="d0H-kE-IWx"/>
|
||||
</mask>
|
||||
</variation>
|
||||
<variation key="heightClass=regular">
|
||||
<mask key="constraints">
|
||||
<include reference="t9j-kf-yze"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="W1i-v6-zbz" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="6Tm-PS-VWZ"/>
|
||||
<constraint firstItem="sRd-zd-xSl" firstAttribute="centerX" secondItem="W1i-v6-zbz" secondAttribute="centerX" id="7AE-Qf-1L3"/>
|
||||
<constraint firstAttribute="trailing" secondItem="W1i-v6-zbz" secondAttribute="trailing" id="7ka-f7-sqc"/>
|
||||
<constraint firstItem="sRd-zd-xSl" firstAttribute="top" secondItem="W1i-v6-zbz" secondAttribute="bottom" constant="8" id="PTe-W7-QnR"/>
|
||||
<constraint firstItem="W1i-v6-zbz" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="RLh-Jr-7dm"/>
|
||||
<constraint firstAttribute="trailing" secondItem="sRd-zd-xSl" secondAttribute="trailing" priority="750" constant="16" id="Z8f-X6-r4N"/>
|
||||
<constraint firstItem="sRd-zd-xSl" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" priority="750" constant="16" id="hJE-fg-IEX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="sRd-zd-xSl" secondAttribute="bottom" constant="26" id="iwo-vC-EI9"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="closeButton" destination="2xW-dK-D9y" id="RQI-hb-JpS"/>
|
||||
<outlet property="isoLinesButton" destination="edA-Mo-3Vx" id="qoC-8w-EqY"/>
|
||||
<outlet property="outdoorButton" destination="g13-pK-Eig" id="ib1-aw-Qv9"/>
|
||||
<outlet property="subwayButton" destination="4US-fZ-cyg" id="eQB-HR-Wgl"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="137.6953125" y="201.953125"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
final class BottomMenuPresentationController: UIPresentationController {
|
||||
override func containerViewWillLayoutSubviews() {
|
||||
super.containerViewWillLayoutSubviews()
|
||||
(presentedViewController as? BottomMenuViewController)?.chromeView.frame = containerView!.bounds
|
||||
presentedView?.frame = frameOfPresentedViewInContainerView
|
||||
}
|
||||
|
||||
override func presentationTransitionWillBegin() {
|
||||
super.presentationTransitionWillBegin()
|
||||
guard let presentedViewController = presentedViewController as? BottomMenuViewController,
|
||||
let coordinator = presentedViewController.transitionCoordinator,
|
||||
let containerView = containerView else { return }
|
||||
|
||||
containerView.addSubview(presentedView!)
|
||||
presentedViewController.containerView = containerView
|
||||
presentedViewController.chromeView.frame = containerView.bounds
|
||||
presentedViewController.chromeView.alpha = 0
|
||||
|
||||
coordinator.animate(alongsideTransition: { _ in
|
||||
presentedViewController.chromeView.alpha = 1
|
||||
}, completion: nil)
|
||||
}
|
||||
|
||||
override func dismissalTransitionWillBegin() {
|
||||
super.dismissalTransitionWillBegin()
|
||||
guard let presentedViewController = presentedViewController as? BottomMenuViewController,
|
||||
let coordinator = presentedViewController.transitionCoordinator,
|
||||
let presentedView = presentedView else { return }
|
||||
|
||||
coordinator.animate(alongsideTransition: { _ in
|
||||
presentedViewController.chromeView.alpha = 0
|
||||
}, completion: { _ in
|
||||
presentedView.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
final class BottomMenuTransitioning: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
private let isPresentation: Bool
|
||||
|
||||
init(isPresentation: Bool) {
|
||||
self.isPresentation = isPresentation
|
||||
super.init()
|
||||
}
|
||||
|
||||
func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return kDefaultAnimationDuration
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
guard let fromVC = transitionContext.viewController(forKey: .from),
|
||||
let toVC = transitionContext.viewController(forKey: .to) else { return }
|
||||
|
||||
let animatingVC = isPresentation ? toVC : fromVC
|
||||
guard let animatingView = animatingVC.view else { return }
|
||||
|
||||
let finalFrameForVC = transitionContext.finalFrame(for: animatingVC)
|
||||
var initialFrameForVC = finalFrameForVC
|
||||
initialFrameForVC.origin.y += initialFrameForVC.size.height
|
||||
|
||||
let initialFrame = isPresentation ? initialFrameForVC : finalFrameForVC
|
||||
let finalFrame = isPresentation ? finalFrameForVC : initialFrameForVC
|
||||
|
||||
animatingView.frame = initialFrame
|
||||
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext),
|
||||
animations: { animatingView.frame = finalFrame },
|
||||
completion: { _ in
|
||||
transitionContext.completeTransition(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
final class BottomMenuTransitioningManager: NSObject, UIViewControllerTransitioningDelegate {
|
||||
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source _: UIViewController) -> UIPresentationController? {
|
||||
BottomMenuPresentationController(presentedViewController: presented,
|
||||
presenting: presenting)
|
||||
}
|
||||
|
||||
func animationController(forPresented _: UIViewController, presenting _: UIViewController, source _: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
return BottomMenuTransitioning(isPresentation: true)
|
||||
}
|
||||
|
||||
func animationController(forDismissed _: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
return BottomMenuTransitioning(isPresentation: false)
|
||||
}
|
||||
}
|
||||
14
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarBuilder.swift
Normal file
14
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarBuilder.swift
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
@objc class BottomTabBarBuilder: NSObject {
|
||||
@objc static func build(mapViewController: MapViewController, controlsManager: MWMMapViewControlsManager) -> BottomTabBarViewController {
|
||||
let viewController = BottomTabBarViewController(nibName: nil, bundle: nil)
|
||||
let interactor = BottomTabBarInteractor(viewController: viewController,
|
||||
mapViewController: mapViewController,
|
||||
controlsManager: controlsManager)
|
||||
let presenter = BottomTabBarPresenter(interactor: interactor)
|
||||
|
||||
interactor.presenter = presenter
|
||||
viewController.presenter = presenter
|
||||
|
||||
return viewController
|
||||
}
|
||||
}
|
||||
32
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarButton.swift
Normal file
32
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarButton.swift
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import UIKit
|
||||
|
||||
class BottomTabBarButton: MWMButton {
|
||||
@objc override func applyTheme() {
|
||||
if styleName.isEmpty {
|
||||
setStyle(.bottomTabBarButton)
|
||||
}
|
||||
|
||||
for style in StyleManager.shared.getStyle(styleName) where !style.isEmpty && !style.hasExclusion(view: self) {
|
||||
BottomTabBarButtonRenderer.render(self, style: style)
|
||||
}
|
||||
}
|
||||
|
||||
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return bounds.insetBy(dx: kExtendedTabBarTappableMargin, dy: kExtendedTabBarTappableMargin).contains(point)
|
||||
}
|
||||
}
|
||||
|
||||
class BottomTabBarButtonRenderer {
|
||||
class func render(_ control: BottomTabBarButton, style: Style) {
|
||||
UIViewRenderer.renderShadow(control, style: style)
|
||||
UIViewRenderer.renderBorder(control, style: style)
|
||||
|
||||
if let coloring = style.coloring {
|
||||
control.coloring = coloring
|
||||
}
|
||||
if let backgroundColor = style.backgroundColor {
|
||||
control.backgroundColor = backgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
protocol BottomTabBarInteractorProtocol: AnyObject {
|
||||
func openSearch()
|
||||
func openLeftButton()
|
||||
func openBookmarks()
|
||||
func openMenu()
|
||||
}
|
||||
|
||||
class BottomTabBarInteractor {
|
||||
weak var presenter: BottomTabBarPresenterProtocol?
|
||||
private weak var viewController: UIViewController?
|
||||
private weak var mapViewController: MapViewController?
|
||||
private weak var controlsManager: MWMMapViewControlsManager?
|
||||
private let searchManager: SearchOnMapManager
|
||||
|
||||
init(viewController: UIViewController, mapViewController: MapViewController, controlsManager: MWMMapViewControlsManager) {
|
||||
self.viewController = viewController
|
||||
self.mapViewController = mapViewController
|
||||
self.controlsManager = controlsManager
|
||||
self.searchManager = mapViewController.searchManager
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomTabBarInteractor: BottomTabBarInteractorProtocol {
|
||||
func openSearch() {
|
||||
searchManager.isSearching ? searchManager.close() : searchManager.startSearching(isRouting: false)
|
||||
}
|
||||
|
||||
func openLeftButton() {
|
||||
switch Settings.leftButtonType {
|
||||
case .addPlace:
|
||||
if let delegate = controlsManager as? BottomMenuDelegate {
|
||||
delegate.addPlace()
|
||||
}
|
||||
case .settings:
|
||||
mapViewController?.openSettings()
|
||||
case .recordTrack:
|
||||
let mapViewController = MapViewController.shared()!
|
||||
let trackRecorder: TrackRecordingManager = .shared
|
||||
switch trackRecorder.recordingState {
|
||||
case .active:
|
||||
mapViewController.showTrackRecordingPlacePage()
|
||||
case .inactive:
|
||||
trackRecorder.start { result in
|
||||
switch result {
|
||||
case .success:
|
||||
mapViewController.showTrackRecordingPlacePage()
|
||||
case .failure:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
mapViewController?.openAbout()
|
||||
}
|
||||
}
|
||||
|
||||
func openBookmarks() {
|
||||
mapViewController?.bookmarksCoordinator.open()
|
||||
}
|
||||
|
||||
func openMenu() {
|
||||
guard let state = controlsManager?.menuState else {
|
||||
fatalError("ERROR: Failed to retrieve the current MapViewControlsManager's state.")
|
||||
}
|
||||
switch state {
|
||||
case .inactive: controlsManager?.menuState = .active
|
||||
case .active: controlsManager?.menuState = .inactive
|
||||
case .hidden:
|
||||
// When the current controls manager's state is hidden, accidental taps on the menu button during the hiding animation should be skipped.
|
||||
break;
|
||||
case .layers: fallthrough
|
||||
@unknown default: fatalError("ERROR: Unexpected MapViewControlsManager's state: \(state)")
|
||||
}
|
||||
}
|
||||
}
|
||||
37
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarPresenter.swift
Normal file
37
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarPresenter.swift
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
protocol BottomTabBarPresenterProtocol: AnyObject {
|
||||
func configure()
|
||||
func onLeftButtonPressed()
|
||||
func onSearchButtonPressed()
|
||||
func onBookmarksButtonPressed()
|
||||
func onMenuButtonPressed()
|
||||
}
|
||||
|
||||
class BottomTabBarPresenter: NSObject {
|
||||
private let interactor: BottomTabBarInteractorProtocol
|
||||
|
||||
init(interactor: BottomTabBarInteractorProtocol) {
|
||||
self.interactor = interactor
|
||||
}
|
||||
}
|
||||
|
||||
extension BottomTabBarPresenter: BottomTabBarPresenterProtocol {
|
||||
func configure() {
|
||||
}
|
||||
|
||||
func onLeftButtonPressed() {
|
||||
interactor.openLeftButton()
|
||||
}
|
||||
|
||||
func onSearchButtonPressed() {
|
||||
interactor.openSearch()
|
||||
}
|
||||
|
||||
func onBookmarksButtonPressed() {
|
||||
interactor.openBookmarks()
|
||||
}
|
||||
|
||||
func onMenuButtonPressed() {
|
||||
interactor.openMenu()
|
||||
}
|
||||
}
|
||||
|
||||
28
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarView.swift
Normal file
28
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarView.swift
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
let kExtendedTabBarTappableMargin: CGFloat = -15
|
||||
|
||||
final class BottomTabBarView: SolidTouchView {
|
||||
|
||||
@IBOutlet var mainButtonsView: ExtendedBottomTabBarContainerView!
|
||||
|
||||
override var placePageAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return alternative(iPhone: [], iPad: [.bottom])
|
||||
}
|
||||
|
||||
override var widgetsAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return [.bottom]
|
||||
}
|
||||
|
||||
override var sideButtonsAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return [.bottom]
|
||||
}
|
||||
|
||||
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return bounds.insetBy(dx: kExtendedTabBarTappableMargin, dy: kExtendedTabBarTappableMargin).contains(point)
|
||||
}
|
||||
}
|
||||
|
||||
final class ExtendedBottomTabBarContainerView: UIView {
|
||||
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
return bounds.insetBy(dx: kExtendedTabBarTappableMargin, dy: kExtendedTabBarTappableMargin).contains(point)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
class BottomTabBarViewController: UIViewController {
|
||||
var presenter: BottomTabBarPresenterProtocol!
|
||||
|
||||
@IBOutlet var leftButton: MWMButton?
|
||||
@IBOutlet var searchButton: MWMButton?
|
||||
@IBOutlet var searchConstraintWithLeftButton: NSLayoutConstraint?
|
||||
@IBOutlet var searchConstraintWithoutLeftButton: NSLayoutConstraint?
|
||||
@IBOutlet var bookmarksButton: MWMButton?
|
||||
@IBOutlet var bookmarksConstraintWithLeftButton: NSLayoutConstraint?
|
||||
@IBOutlet var bookmarksConstraintWithoutLeftButton: NSLayoutConstraint?
|
||||
@IBOutlet var moreButton: MWMButton?
|
||||
@IBOutlet var downloadBadge: UIView?
|
||||
|
||||
private var avaliableArea = CGRect.zero
|
||||
@objc var isHidden: Bool = false {
|
||||
didSet {
|
||||
updateFrame(animated: true)
|
||||
}
|
||||
}
|
||||
@objc var isApplicationBadgeHidden: Bool = true {
|
||||
didSet {
|
||||
updateBadge()
|
||||
}
|
||||
}
|
||||
var tabBarView: BottomTabBarView {
|
||||
return view as! BottomTabBarView
|
||||
}
|
||||
@objc static var controller: BottomTabBarViewController? {
|
||||
return MWMMapViewControlsManager.manager()?.tabBarController
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
presenter.configure()
|
||||
|
||||
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: nil) { _ in
|
||||
DispatchQueue.main.async {
|
||||
self.updateLeftButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
leftButton?.imageView?.contentMode = .scaleAspectFit
|
||||
updateBadge()
|
||||
}
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
updateLeftButton()
|
||||
}
|
||||
|
||||
static func updateAvailableArea(_ frame: CGRect) {
|
||||
BottomTabBarViewController.controller?.updateAvailableArea(frame)
|
||||
}
|
||||
|
||||
@IBAction func onSearchButtonPressed(_ sender: Any) {
|
||||
presenter.onSearchButtonPressed()
|
||||
}
|
||||
|
||||
@IBAction func onLeftButtonPressed(_ sender: Any) {
|
||||
presenter.onLeftButtonPressed()
|
||||
}
|
||||
|
||||
@IBAction func onBookmarksButtonPressed(_ sender: Any) {
|
||||
presenter.onBookmarksButtonPressed()
|
||||
}
|
||||
|
||||
@IBAction func onMenuButtonPressed(_ sender: Any) {
|
||||
presenter.onMenuButtonPressed()
|
||||
}
|
||||
|
||||
private func updateAvailableArea(_ frame:CGRect) {
|
||||
avaliableArea = frame
|
||||
updateFrame(animated: false)
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
|
||||
private func updateFrame(animated: Bool) {
|
||||
if avaliableArea == .zero {
|
||||
return
|
||||
}
|
||||
let newFrame = CGRect(x: avaliableArea.minX,
|
||||
y: isHidden ? avaliableArea.minY + avaliableArea.height : avaliableArea.minY,
|
||||
width: avaliableArea.width,
|
||||
height: avaliableArea.height)
|
||||
let alpha:CGFloat = isHidden ? 0 : 1
|
||||
if animated {
|
||||
UIView.animate(withDuration: kDefaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: [.beginFromCurrentState],
|
||||
animations: {
|
||||
self.view.frame = newFrame
|
||||
self.view.alpha = alpha
|
||||
}, completion: nil)
|
||||
} else {
|
||||
self.view.frame = newFrame
|
||||
self.view.alpha = alpha
|
||||
}
|
||||
}
|
||||
|
||||
private func updateLeftButton() {
|
||||
let leftButtonType = Settings.leftButtonType
|
||||
if leftButtonType == .hidden {
|
||||
leftButton?.isHidden = true
|
||||
|
||||
if let searchConstraintWithLeftButton, let searchConstraintWithoutLeftButton, let bookmarksConstraintWithLeftButton, let bookmarksConstraintWithoutLeftButton {
|
||||
NSLayoutConstraint.activate([searchConstraintWithoutLeftButton, bookmarksConstraintWithoutLeftButton])
|
||||
NSLayoutConstraint.deactivate([searchConstraintWithLeftButton, bookmarksConstraintWithLeftButton])
|
||||
}
|
||||
} else {
|
||||
leftButton?.isHidden = false
|
||||
|
||||
leftButton?.setTitle(nil, for: .normal)
|
||||
leftButton?.setImage(leftButtonType.image, for: .normal)
|
||||
leftButton?.accessibilityLabel = leftButtonType.description;
|
||||
|
||||
if let searchConstraintWithLeftButton, let searchConstraintWithoutLeftButton, let bookmarksConstraintWithLeftButton, let bookmarksConstraintWithoutLeftButton {
|
||||
NSLayoutConstraint.activate([searchConstraintWithLeftButton, bookmarksConstraintWithLeftButton])
|
||||
NSLayoutConstraint.deactivate([searchConstraintWithoutLeftButton, bookmarksConstraintWithoutLeftButton])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateBadge() {
|
||||
downloadBadge?.isHidden = isApplicationBadgeHidden
|
||||
}
|
||||
}
|
||||
148
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarViewController.xib
Normal file
148
iphone/Maps/UI/BottomMenu/TabBar/BottomTabBarViewController.xib
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="24128" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||
<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="BottomTabBarViewController" customModule="CoMaps" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="bookmarksButton" destination="dgG-ki-3tB" id="md5-3T-9tb"/>
|
||||
<outlet property="bookmarksConstraintWithLeftButton" destination="Jc7-nc-elY" id="gW7-8e-E6m"/>
|
||||
<outlet property="bookmarksConstraintWithoutLeftButton" destination="NRb-vj-MFg" id="C3Z-Ia-D6i"/>
|
||||
<outlet property="downloadBadge" destination="uDI-ZC-4wx" id="fAf-cy-Ozn"/>
|
||||
<outlet property="leftButton" destination="dzf-7Z-N6a" id="LMZ-H7-ftQ"/>
|
||||
<outlet property="moreButton" destination="svD-yi-GrZ" id="kjk-ZW-nZN"/>
|
||||
<outlet property="searchButton" destination="No0-ld-JX3" id="m5F-UT-j94"/>
|
||||
<outlet property="searchConstraintWithLeftButton" destination="tDb-w1-ueQ" id="WaI-Xb-1bu"/>
|
||||
<outlet property="searchConstraintWithoutLeftButton" destination="cQg-jW-uSD" id="cMy-EC-G07"/>
|
||||
<outlet property="view" destination="zuH-WU-hiP" id="eoa-4I-wKs"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="zuH-WU-hiP" customClass="BottomTabBarView" customModule="CoMaps" customModuleProvider="target" propertyAccessControl="none">
|
||||
<rect key="frame" x="0.0" y="0.0" width="373" height="84"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vum-s3-PHx" userLabel="MainButtons" customClass="ExtendedBottomTabBarContainerView" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="373" height="48"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleAspectFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dzf-7Z-N6a" userLabel="LeftButton" customClass="BottomTabBarButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="22.5" y="0.0" width="48" height="48"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="helpButton"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="dzf-7Z-N6a" secondAttribute="height" id="qNJ-0K-sK0"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="30"/>
|
||||
<inset key="imageEdgeInsets" minX="9" minY="9" maxX="9" maxY="9"/>
|
||||
<state key="normal" image="info.circle" catalog="system"/>
|
||||
<connections>
|
||||
<action selector="onLeftButtonPressed:" destination="-1" eventType="touchUpInside" id="1gx-P2-sRJ"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="249" horizontalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="No0-ld-JX3" userLabel="Search" customClass="BottomTabBarButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="116" y="0.0" width="48" height="48"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="searchButton"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="No0-ld-JX3" secondAttribute="height" id="2bW-fc-Hsh"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="ic_menu_search"/>
|
||||
<connections>
|
||||
<action selector="onSearchButtonPressed:" destination="-1" eventType="touchUpInside" id="0D5-RB-HBQ"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleAspectFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dgG-ki-3tB" userLabel="Bookmarks" customClass="BottomTabBarButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="209" y="0.0" width="48" height="48"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="bookmarksButton"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="dgG-ki-3tB" secondAttribute="height" id="o3b-it-lrV"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="ic_menu_bookmark_list"/>
|
||||
<connections>
|
||||
<action selector="onBookmarksButtonPressed:" destination="-1" eventType="touchUpInside" id="9Z1-eg-xth"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleAspectFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="svD-yi-GrZ" userLabel="Menu" customClass="BottomTabBarButton" customModule="CoMaps" customModuleProvider="target">
|
||||
<rect key="frame" x="302.5" y="0.0" width="48" height="48"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="menuButton"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="svD-yi-GrZ" secondAttribute="height" id="gmG-3a-Mqe"/>
|
||||
</constraints>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" image="ic_menu"/>
|
||||
<connections>
|
||||
<action selector="onMenuButtonPressed:" destination="-1" eventType="touchUpInside" id="rzb-y4-nR1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uDI-ZC-4wx" userLabel="DownloadBadge">
|
||||
<rect key="frame" x="329.5" y="11" width="10" height="10"/>
|
||||
<color key="backgroundColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" notEnabled="YES"/>
|
||||
</accessibility>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="10" id="tEP-Xi-qnU"/>
|
||||
<constraint firstAttribute="height" constant="10" id="wNg-5Z-7AO"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="Badge"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
</subviews>
|
||||
<accessibility key="accessibilityConfiguration" identifier="MainButtons"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="48" id="69A-eu-uLp"/>
|
||||
<constraint firstItem="No0-ld-JX3" firstAttribute="centerY" secondItem="vum-s3-PHx" secondAttribute="centerY" id="8nL-zT-Y7b"/>
|
||||
<constraint firstItem="No0-ld-JX3" firstAttribute="height" secondItem="vum-s3-PHx" secondAttribute="height" id="9eR-I7-7at"/>
|
||||
<constraint firstItem="svD-yi-GrZ" firstAttribute="height" secondItem="vum-s3-PHx" secondAttribute="height" id="Fde-um-JL6"/>
|
||||
<constraint firstItem="dgG-ki-3tB" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" multiplier="1.25" id="Jc7-nc-elY"/>
|
||||
<constraint firstItem="dgG-ki-3tB" firstAttribute="centerY" secondItem="vum-s3-PHx" secondAttribute="centerY" id="JjT-sc-hIY"/>
|
||||
<constraint firstItem="dgG-ki-3tB" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" priority="900" id="NRb-vj-MFg"/>
|
||||
<constraint firstItem="svD-yi-GrZ" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" multiplier="1.75" id="Q0b-gd-HwS"/>
|
||||
<constraint firstItem="dgG-ki-3tB" firstAttribute="height" secondItem="vum-s3-PHx" secondAttribute="height" id="Rs8-Hl-CAc"/>
|
||||
<constraint firstItem="uDI-ZC-4wx" firstAttribute="centerX" secondItem="svD-yi-GrZ" secondAttribute="centerX" constant="8" id="XNb-Ba-Hn7"/>
|
||||
<constraint firstItem="dzf-7Z-N6a" firstAttribute="centerY" secondItem="vum-s3-PHx" secondAttribute="centerY" id="Zug-zY-KIX"/>
|
||||
<constraint firstItem="No0-ld-JX3" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" multiplier="0.25" priority="900" id="cQg-jW-uSD"/>
|
||||
<constraint firstItem="svD-yi-GrZ" firstAttribute="centerY" secondItem="vum-s3-PHx" secondAttribute="centerY" id="sja-hO-YY3"/>
|
||||
<constraint firstItem="No0-ld-JX3" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" multiplier="0.75" id="tDb-w1-ueQ"/>
|
||||
<constraint firstItem="dzf-7Z-N6a" firstAttribute="centerX" secondItem="vum-s3-PHx" secondAttribute="centerX" multiplier="0.25" id="u3G-gY-98J"/>
|
||||
<constraint firstItem="dzf-7Z-N6a" firstAttribute="height" secondItem="vum-s3-PHx" secondAttribute="height" id="yTg-8g-H1p"/>
|
||||
<constraint firstItem="uDI-ZC-4wx" firstAttribute="centerY" secondItem="svD-yi-GrZ" secondAttribute="centerY" constant="-8" id="yq3-ui-IaL"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="cQg-jW-uSD"/>
|
||||
<exclude reference="NRb-vj-MFg"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="aaw-Hz-zma"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vum-s3-PHx" firstAttribute="top" secondItem="zuH-WU-hiP" secondAttribute="top" id="PQS-ro-25e"/>
|
||||
<constraint firstItem="vum-s3-PHx" firstAttribute="leading" secondItem="zuH-WU-hiP" secondAttribute="leading" id="kza-JN-Dul"/>
|
||||
<constraint firstAttribute="trailing" secondItem="vum-s3-PHx" secondAttribute="trailing" id="sM6-P2-rN9"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="mainButtonsView" destination="vum-s3-PHx" id="fBi-DA-orA"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="72" y="254"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="ic_menu" width="48" height="48"/>
|
||||
<image name="ic_menu_bookmark_list" width="48" height="48"/>
|
||||
<image name="ic_menu_search" width="48" height="48"/>
|
||||
<image name="info.circle" catalog="system" width="128" height="123"/>
|
||||
</resources>
|
||||
</document>
|
||||
Loading…
Add table
Add a link
Reference in a new issue