From 41979b1104581199d6e758ad2d654cfbf56f488d Mon Sep 17 00:00:00 2001 From: Kiryl Kaveryn Date: Tue, 5 Nov 2024 16:55:28 +0400 Subject: [PATCH] [ios] implement Track PlacePage UI Signed-off-by: Kiryl Kaveryn --- iphone/Maps/Classes/Components/MWMButton.h | 3 +- iphone/Maps/Classes/Components/MWMButton.m | 25 +-- iphone/Maps/Classes/MapViewController.mm | 21 +- iphone/Maps/Maps.xcodeproj/project.pbxproj | 12 +- .../EditTrackViewController.swift | 39 ++-- .../Components/ActionBarViewController.swift | 179 +++++++++------- .../ElevationDetailsBuilder.swift | 5 +- .../ElevationDetailsPresenter.swift | 2 - .../ElevationDetailsViewController.xib | 28 ++- .../ElevationProfileBuilder.swift | 13 +- .../ElevationProfileFormatter.swift | 67 ++++++ .../ElevationProfilePresenter.swift | 193 ++++++------------ .../ElevationProfileViewController.swift | 61 +++--- .../PlacePageBookmarkViewController.swift | 42 +++- .../PlacePageHeaderPresenter.swift | 2 + .../PlacePageHeaderViewController.swift | 10 + .../PlacePagePreviewViewController.swift | 9 +- iphone/Maps/UI/PlacePage/PlacePage.storyboard | 83 +++----- .../Maps/UI/PlacePage/PlacePageBuilder.swift | 30 ++- .../UI/PlacePage/PlacePageInteractor.swift | 24 +-- .../ActionBar/MWMActionBarButton.h | 1 + .../ActionBar/MWMActionBarButton.m | 5 + .../Layouts/PlacePageCommonLayout.swift | 4 +- .../Layouts/PlacePageElevationLayout.swift | 57 ------ .../Layouts/PlacePageTrackLayout.swift | 129 ++++++++++++ .../PlacePageManager/MWMPlacePageManager.mm | 30 ++- .../MWMPlacePageManagerHelper.h | 2 + .../MWMPlacePageManagerHelper.mm | 10 + .../Util/OpeinigHoursLocalization.swift | 3 +- 29 files changed, 617 insertions(+), 472 deletions(-) create mode 100644 iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileFormatter.swift delete mode 100644 iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageElevationLayout.swift create mode 100644 iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageTrackLayout.swift diff --git a/iphone/Maps/Classes/Components/MWMButton.h b/iphone/Maps/Classes/Components/MWMButton.h index d6f8d32a1d..fb5e59f9d4 100644 --- a/iphone/Maps/Classes/Components/MWMButton.h +++ b/iphone/Maps/Classes/Components/MWMButton.h @@ -5,7 +5,8 @@ typedef NS_ENUM(NSUInteger, MWMButtonColoring) MWMButtonColoringBlack, MWMButtonColoringWhite, MWMButtonColoringWhiteText, - MWMButtonColoringGray + MWMButtonColoringGray, + MWMButtonColoringRed }; @interface MWMButton : UIButton diff --git a/iphone/Maps/Classes/Components/MWMButton.m b/iphone/Maps/Classes/Components/MWMButton.m index d807c815a0..9a82173ab2 100644 --- a/iphone/Maps/Classes/Components/MWMButton.m +++ b/iphone/Maps/Classes/Components/MWMButton.m @@ -71,6 +71,9 @@ static NSString * const kSelectedPattern = @"%@_selected_%@"; case MWMButtonColoringWhiteText: self.tintColor = [UIColor whitePrimaryTextHighlighted]; break; + case MWMButtonColoringRed: + self.tintColor = [UIColor buttonRed]; + break; case MWMButtonColoringWhite: case MWMButtonColoringOther: break; @@ -100,6 +103,7 @@ static NSString * const kSelectedPattern = @"%@_selected_%@"; case MWMButtonColoringBlue: case MWMButtonColoringOther: case MWMButtonColoringGray: + case MWMButtonColoringRed: break; } } @@ -137,28 +141,13 @@ static NSString * const kSelectedPattern = @"%@_selected_%@"; case MWMButtonColoringGray: self.tintColor = [UIColor blackHintText]; break; + case MWMButtonColoringRed: + self.tintColor = [UIColor red]; + break; case MWMButtonColoringOther: self.imageView.image = [self imageForState:UIControlStateNormal]; break; } } -- (void)setColoringName:(NSString *)coloring -{ - if ([coloring isEqualToString:@"MWMBlue"]) - self.coloring = MWMButtonColoringBlue; - else if ([coloring isEqualToString:@"MWMBlack"]) - self.coloring = MWMButtonColoringBlack; - else if ([coloring isEqualToString:@"MWMWhite"]) - self.coloring = MWMButtonColoringWhite; - else if ([coloring isEqualToString:@"MWMWhiteText"]) - self.coloring = MWMButtonColoringWhiteText; - else if ([coloring isEqualToString:@"MWMOther"]) - self.coloring = MWMButtonColoringOther; - else if ([coloring isEqualToString:@"MWMGray"]) - self.coloring = MWMButtonColoringGray; - else - NSAssert(false, @"Invalid UIButton's coloring!"); -} - @end diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index f88804696e..f91e1d560b 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -110,22 +110,17 @@ NSString *const kSettingsSegue = @"Map2Settings"; #pragma mark - Map Navigation -- (void)showOrUpdatePlacePage { - if (!PlacePageData.hasData) { - return; - } - +- (void)showOrUpdatePlacePage:(PlacePageData *)data { self.controlsManager.trafficButtonHidden = YES; - if (self.placePageVC != nil) { - [PlacePageBuilder update:(PlacePageViewController *)self.placePageVC]; + [PlacePageBuilder update:(PlacePageViewController *)self.placePageVC with:data]; return; } - [self showRegularPlacePage]; + [self showPlacePageFor:data]; } -- (void)showRegularPlacePage { - self.placePageVC = [PlacePageBuilder build]; +- (void)showPlacePageFor:(PlacePageData *)data { + self.placePageVC = [PlacePageBuilder buildFor:data]; self.placePageContainer.hidden = NO; self.placePageVC.view.translatesAutoresizingMaskIntoConstraints = NO; [self.placePageContainer addSubview:self.placePageVC.view]; @@ -191,7 +186,11 @@ NSString *const kSettingsSegue = @"Map2Settings"; } - (void)onMapObjectSelected { - [self showOrUpdatePlacePage]; + if (!PlacePageData.hasData) { + return; + } + PlacePageData * data = [[PlacePageData alloc] initWithLocalizationProvider:[[OpeinigHoursLocalization alloc] init]]; + [self showOrUpdatePlacePage:data]; } - (void)onMapObjectUpdated { diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 1bd7840f1b..b20f72c8e5 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -340,7 +340,7 @@ 990F33B624BC915200D0F426 /* SearchActionBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 990F33B524BC915200D0F426 /* SearchActionBarView.swift */; }; 9917D17F2397B1D600A7E06E /* IPadModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9917D17E2397B1D600A7E06E /* IPadModalPresentationController.swift */; }; 991FCA2423B11E61009AD684 /* BookmarksStyleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 991FCA2323B11E61009AD684 /* BookmarksStyleSheet.swift */; }; - 993DF0B523F6B2EF00AC231A /* PlacePageElevationLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993DF0B423F6B2EF00AC231A /* PlacePageElevationLayout.swift */; }; + 993DF0B523F6B2EF00AC231A /* PlacePageTrackLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */; }; 993DF0C823F6BD0600AC231A /* ElevationDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993DF0C323F6BD0600AC231A /* ElevationDetailsViewController.swift */; }; 993DF0C923F6BD0600AC231A /* ElevationDetailsBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993DF0C423F6BD0600AC231A /* ElevationDetailsBuilder.swift */; }; 993DF0CA23F6BD0600AC231A /* ElevationDetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 993DF0C523F6BD0600AC231A /* ElevationDetailsViewController.xib */; }; @@ -512,6 +512,7 @@ ED8270F02C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */; }; ED9857082C4ED02D00694F6C /* MailComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED9857072C4ED02D00694F6C /* MailComposer.swift */; }; ED9966802B94FBC20083CE55 /* ColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED99667D2B94FBC20083CE55 /* ColorPicker.swift */; }; + EDA1EAA42CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA1EAA32CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift */; }; EDBD68072B625724005DD151 /* LocationServicesDisabledAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = EDBD68062B625724005DD151 /* LocationServicesDisabledAlert.xib */; }; EDBD680B2B62572E005DD151 /* LocationServicesDisabledAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDBD680A2B62572E005DD151 /* LocationServicesDisabledAlert.swift */; }; EDC3573B2B7B5029001AE9CA /* CALayer+SetCorner.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC3573A2B7B5029001AE9CA /* CALayer+SetCorner.swift */; }; @@ -1261,7 +1262,7 @@ 990F33B524BC915200D0F426 /* SearchActionBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchActionBarView.swift; sourceTree = ""; }; 9917D17E2397B1D600A7E06E /* IPadModalPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPadModalPresentationController.swift; sourceTree = ""; }; 991FCA2323B11E61009AD684 /* BookmarksStyleSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksStyleSheet.swift; sourceTree = ""; }; - 993DF0B423F6B2EF00AC231A /* PlacePageElevationLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageElevationLayout.swift; sourceTree = ""; }; + 993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageTrackLayout.swift; sourceTree = ""; }; 993DF0C323F6BD0600AC231A /* ElevationDetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElevationDetailsViewController.swift; sourceTree = ""; }; 993DF0C423F6BD0600AC231A /* ElevationDetailsBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElevationDetailsBuilder.swift; sourceTree = ""; }; 993DF0C523F6BD0600AC231A /* ElevationDetailsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ElevationDetailsViewController.xib; sourceTree = ""; }; @@ -1477,6 +1478,7 @@ ED8270EF2C2071A3005966DA /* SettingsTableViewDetailedSwitchCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewDetailedSwitchCell.swift; sourceTree = ""; }; ED9857072C4ED02D00694F6C /* MailComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposer.swift; sourceTree = ""; }; ED99667D2B94FBC20083CE55 /* ColorPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPicker.swift; sourceTree = ""; }; + EDA1EAA32CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElevationProfileFormatter.swift; sourceTree = ""; }; EDBD68062B625724005DD151 /* LocationServicesDisabledAlert.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LocationServicesDisabledAlert.xib; sourceTree = ""; }; EDBD680A2B62572E005DD151 /* LocationServicesDisabledAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationServicesDisabledAlert.swift; sourceTree = ""; }; EDC3573A2B7B5029001AE9CA /* CALayer+SetCorner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+SetCorner.swift"; sourceTree = ""; }; @@ -3031,7 +3033,7 @@ children = ( 99C6532123F2F506004322F3 /* IPlacePageLayout.swift */, 99F3EB0223F4178200C713F8 /* PlacePageCommonLayout.swift */, - 993DF0B423F6B2EF00AC231A /* PlacePageElevationLayout.swift */, + 993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */, ); path = Layouts; sourceTree = ""; @@ -3052,6 +3054,7 @@ isa = PBXGroup; children = ( 99514BB223E82B450085D3A7 /* ElevationProfilePresenter.swift */, + EDA1EAA32CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift */, 99514BB423E82B450085D3A7 /* ElevationProfileViewController.swift */, 99514BB523E82B450085D3A7 /* ElevationProfileBuilder.swift */, 99DEF9D623E420F6006BFD21 /* ElevationProfileDescriptionCell.swift */, @@ -4534,7 +4537,7 @@ 47E3C72D2111E6A2008B3B27 /* FadeTransitioning.swift in Sources */, 34845DAF1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift in Sources */, EDFDFB482B7139670013A44C /* SocialMedia.swift in Sources */, - 993DF0B523F6B2EF00AC231A /* PlacePageElevationLayout.swift in Sources */, + 993DF0B523F6B2EF00AC231A /* PlacePageTrackLayout.swift in Sources */, 44360A0D2A7D34990016F412 /* TransportRuler.swift in Sources */, CD6E8677226774C700D1EDF7 /* CPConstants.swift in Sources */, 99A906DE23F6F7030005872B /* PlacePageBookmarkViewController.swift in Sources */, @@ -4716,6 +4719,7 @@ 3444DFCD1F1760B900E73099 /* WidgetsArea.swift in Sources */, 34D3B03C1E389D05004100F9 /* MWMEditorSwitchTableViewCell.m in Sources */, 34AB66411FC5AA330078E451 /* RouteManagerTransitioningManager.swift in Sources */, + EDA1EAA42CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift in Sources */, 996D108A24E3DBF2002DD0E2 /* BookmarksCoordinator.swift in Sources */, 3454D7CE1E07F045004AF2AD /* UIFont+MapsMeFonts.m in Sources */, 99A906E123F6F7030005872B /* PlacePageButtonsViewController.swift in Sources */, diff --git a/iphone/Maps/UI/EditBookmark/EditTrackViewController.swift b/iphone/Maps/UI/EditBookmark/EditTrackViewController.swift index f82e3d956a..ad25e06880 100644 --- a/iphone/Maps/UI/EditBookmark/EditTrackViewController.swift +++ b/iphone/Maps/UI/EditBookmark/EditTrackViewController.swift @@ -17,6 +17,7 @@ final class EditTrackViewController: MWMTableViewController { private var editingCompleted: (Bool) -> Void + private var placePageData: PlacePageData? private let trackId: MWMTrackID private var trackTitle: String? private var trackGroupTitle: String? @@ -24,25 +25,21 @@ final class EditTrackViewController: MWMTableViewController { private var trackColor: UIColor private let bookmarksManager = BookmarksManager.shared() - + + @objc init(trackId: MWMTrackID, editCompletion completion: @escaping (Bool) -> Void) { self.trackId = trackId - let bm = BookmarksManager.shared() - let track = bm.track(withId: trackId) - - trackTitle = track.trackName - trackColor = track.trackColor + let track = bookmarksManager.track(withId: trackId) + self.trackTitle = track.trackName + self.trackColor = track.trackColor - let category = bm.category(forTrackId: trackId) - trackGroupId = category.categoryId - trackGroupTitle = category.title - - - editingCompleted = completion + let category = bookmarksManager.category(forTrackId: trackId) + self.trackGroupId = category.categoryId + self.trackGroupTitle = category.title + self.editingCompleted = completion super.init(style: .grouped) - } override func viewWillAppear(_ animated: Bool) { @@ -184,10 +181,22 @@ extension EditTrackViewController: BookmarkTitleCellDelegate { } } +// MARK: - MWMButtonCellDelegate + extension EditTrackViewController: MWMButtonCellDelegate { func cellDidPressButton(_ cell: UITableViewCell) { - bookmarksManager.deleteTrack(trackId) - goBack() + guard let indexPath = tableView.indexPath(for: cell) else { + fatalError("Invalid cell") + } + switch Sections(rawValue: indexPath.section) { + case .info: + break + case .delete: + bookmarksManager.deleteTrack(trackId) + goBack() + default: + fatalError("Invalid section") + } } } diff --git a/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift b/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift index 20227d0439..78bd180373 100644 --- a/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift @@ -2,11 +2,11 @@ protocol ActionBarViewControllerDelegate: AnyObject { func actionBar(_ actionBar: ActionBarViewController, didPressButton type: ActionBarButtonType) } -class ActionBarViewController: UIViewController { +final class ActionBarViewController: UIViewController { @IBOutlet var stackView: UIStackView! - var downloadButton: ActionBarButton? = nil - var bookmarkButton: ActionBarButton? = nil - var popoverSourceView: UIView? { + private(set) var downloadButton: ActionBarButton? = nil + private(set) var bookmarkButton: ActionBarButton? = nil + private var popoverSourceView: UIView? { stackView.arrangedSubviews.last } @@ -19,6 +19,13 @@ class ActionBarViewController: UIViewController { weak var delegate: ActionBarViewControllerDelegate? + override func viewDidLoad() { + super.viewDidLoad() + configureButtons() + } + + // MARK: - Private methods + private func configureButtons() { if placePageData.isRoutePoint { visibleButtons.append(.routeRemoveStop) @@ -40,66 +47,7 @@ class ActionBarViewController: UIViewController { configButton4() } - for buttonType in visibleButtons { - let (selected, enabled) = buttonState(buttonType) - let button = ActionBarButton(delegate: self, - buttonType: buttonType, - isSelected: selected, - isEnabled: enabled) - stackView.addArrangedSubview(button) - if buttonType == .download { - downloadButton = button - updateDownloadButtonState(placePageData.mapNodeAttributes!.nodeStatus) - } - if buttonType == .bookmark { - bookmarkButton = button - } - } - } - - func resetButtons() { - stackView.arrangedSubviews.forEach { - stackView.removeArrangedSubview($0) - $0.removeFromSuperview() - } - visibleButtons.removeAll() - additionalButtons.removeAll() - downloadButton = nil - bookmarkButton = nil - configureButtons() - } - - override func viewDidLoad() { - super.viewDidLoad() - - configureButtons() - } - - func updateDownloadButtonState(_ nodeStatus: MapNodeStatus) { - guard let downloadButton = downloadButton, let mapNodeAttributes = placePageData.mapNodeAttributes else { return } - switch mapNodeAttributes.nodeStatus { - case .downloading: - downloadButton.mapDownloadProgress?.state = .progress - case .applying, .inQueue: - downloadButton.mapDownloadProgress?.state = .spinner - case .error: - downloadButton.mapDownloadProgress?.state = .failed - case .onDisk, .undefined, .onDiskOutOfDate: - downloadButton.mapDownloadProgress?.state = .completed - case .notDownloaded, .partly: - downloadButton.mapDownloadProgress?.state = .normal - @unknown default: - fatalError() - } - } - - func updateBookmarkButtonState(isSelected: Bool) { - guard let bookmarkButton else { return } - if !isSelected && BookmarksManager.shared().hasRecentlyDeletedBookmark() { - bookmarkButton.setBookmarkButtonState(.recover) - return - } - bookmarkButton.setBookmarkButtonState(isSelected ? .delete : .save) + setupButtonsState() } private func configButton1() { @@ -134,11 +82,20 @@ class ActionBarViewController: UIViewController { private func configButton2() { var buttons: [ActionBarButtonType] = [] - if canAddStop { - buttons.append(.routeAddStop) + switch placePageData.objectType { + case .POI, .bookmark: + if canAddStop { + buttons.append(.routeAddStop) + } + buttons.append(.bookmark) + case .track: + buttons.append(.track) + case .trackRecording: + // TODO: implement for track recording + break + @unknown default: + fatalError() } - buttons.append(.bookmark) - assert(buttons.count > 0) visibleButtons.append(buttons[0]) if buttons.count > 1 { @@ -155,6 +112,40 @@ class ActionBarViewController: UIViewController { additionalButtons.count == 1 ? visibleButtons.append(additionalButtons[0]) : visibleButtons.append(.more) } + private func setupButtonsState() { + for buttonType in visibleButtons { + let (selected, enabled) = buttonState(buttonType) + let button = ActionBarButton(delegate: self, + buttonType: buttonType, + isSelected: selected, + isEnabled: enabled) + stackView.addArrangedSubview(button) + switch buttonType { + case .download: + downloadButton = button + updateDownloadButtonState(placePageData.mapNodeAttributes!.nodeStatus) + case .bookmark: + bookmarkButton = button + default: + break + } + } + } + + private func buttonState(_ buttonType: ActionBarButtonType) -> (selected: Bool, enabled: Bool) { + var selected = false + let enabled = true + switch buttonType { + case .bookmark: + selected = placePageData.bookmarkData != nil + case .track: + selected = placePageData.trackData != nil + default: + break + } + return (selected, enabled) + } + private func showMore() { let actionSheet = UIAlertController(title: placePageData.previewData.title, message: placePageData.previewData.subtitle, @@ -178,22 +169,56 @@ class ActionBarViewController: UIViewController { present(actionSheet, animated: true) } - private func buttonState(_ buttonType: ActionBarButtonType) -> (Bool /* selected */, Bool /* enabled */) { - var selected = false - let enabled = true - if buttonType == .bookmark && placePageData.bookmarkData != nil { - selected = true + + // MARK: - Public methods + + func resetButtons() { + stackView.arrangedSubviews.forEach { + stackView.removeArrangedSubview($0) + $0.removeFromSuperview() } - return (selected, enabled) + visibleButtons.removeAll() + additionalButtons.removeAll() + downloadButton = nil + bookmarkButton = nil + configureButtons() + } + + func updateDownloadButtonState(_ nodeStatus: MapNodeStatus) { + guard let downloadButton = downloadButton, let mapNodeAttributes = placePageData.mapNodeAttributes else { return } + switch mapNodeAttributes.nodeStatus { + case .downloading: + downloadButton.mapDownloadProgress?.state = .progress + case .applying, .inQueue: + downloadButton.mapDownloadProgress?.state = .spinner + case .error: + downloadButton.mapDownloadProgress?.state = .failed + case .onDisk, .undefined, .onDiskOutOfDate: + downloadButton.mapDownloadProgress?.state = .completed + case .notDownloaded, .partly: + downloadButton.mapDownloadProgress?.state = .normal + @unknown default: + fatalError() + } + } + + func updateBookmarkButtonState(isSelected: Bool) { + guard let bookmarkButton else { return } + if !isSelected && BookmarksManager.shared().hasRecentlyDeletedBookmark() { + bookmarkButton.setBookmarkButtonState(.recover) + return + } + bookmarkButton.setBookmarkButtonState(isSelected ? .delete : .save) } } extension ActionBarViewController: ActionBarButtonDelegate { func tapOnButton(with type: ActionBarButtonType) { - if type == .more { + switch type { + case .more: showMore() - return + default: + delegate?.actionBar(self, didPressButton: type) } - delegate?.actionBar(self, didPressButton: type) } } diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsBuilder.swift b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsBuilder.swift index 6ec412269a..5192d45104 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsBuilder.swift +++ b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsBuilder.swift @@ -1,14 +1,13 @@ @objc class ElevationDetailsBuilder: NSObject { @objc static func build(data: PlacePageData) -> UIViewController { - guard let elevationProfileData = data.elevationProfileData else { + guard let elevationProfileData = data.trackData?.elevationProfileData else { + LOG(.critical, "Elevation profile data should not be nil when building elevation details") fatalError() } let viewController = ElevationDetailsViewController(nibName: toString(ElevationDetailsViewController.self), bundle: nil) let router = ElevationDetailsRouter(viewController: viewController) let presenter = ElevationDetailsPresenter(view: viewController, router: router, data: elevationProfileData) - viewController.presenter = presenter - return viewController } } diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsPresenter.swift b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsPresenter.swift index 36f614cd0e..964a277fd9 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsPresenter.swift +++ b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsPresenter.swift @@ -20,8 +20,6 @@ class ElevationDetailsPresenter { extension ElevationDetailsPresenter: ElevationDetailsPresenterProtocol { func configure() { view?.setDifficulty(data.difficulty) -// view?.setExtendedDifficultyGrade(data.extendedDifficultyGrade ?? "") -// view?.setDifficultyDescription(data.extendedDifficultyDescription ?? "") } func onOkButtonPressed() { diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsViewController.xib b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsViewController.xib index dd803640c7..d0356a835c 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsViewController.xib +++ b/iphone/Maps/UI/PlacePage/Components/ElevationDetails/ElevationDetailsViewController.xib @@ -1,10 +1,11 @@ - + - + + @@ -23,7 +24,7 @@ - + @@ -110,11 +112,15 @@ - + + + + + diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileBuilder.swift b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileBuilder.swift index aba969e77b..ea730965b1 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileBuilder.swift +++ b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileBuilder.swift @@ -1,13 +1,14 @@ +import CoreApi + class ElevationProfileBuilder { - static func build(data: PlacePageData, delegate: ElevationProfileViewControllerDelegate?) -> ElevationProfileViewController { - guard let elevationProfileData = data.elevationProfileData else { - fatalError() - } + static func build(trackInfo: TrackRecordingInfo, + elevationProfileData: ElevationProfileData?, + delegate: ElevationProfileViewControllerDelegate?) -> ElevationProfileViewController { let storyboard = UIStoryboard.instance(.placePage) let viewController = storyboard.instantiateViewController(ofType: ElevationProfileViewController.self); let presenter = ElevationProfilePresenter(view: viewController, - data: elevationProfileData, - imperialUnits: Settings.measurementUnits() == .imperial, + trackInfo: trackInfo, + profileData: elevationProfileData, delegate: delegate) viewController.presenter = presenter diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileFormatter.swift b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileFormatter.swift new file mode 100644 index 0000000000..4a17c5c4c5 --- /dev/null +++ b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileFormatter.swift @@ -0,0 +1,67 @@ +import Chart +import CoreApi + +final class ElevationProfileFormatter { + + private enum Constants { + static let metricToImperialMultiplier: CGFloat = 0.3048 + static var metricAltitudeStep: CGFloat = 50 + static var imperialAltitudeStep: CGFloat = 100 + } + + private let distanceFormatter: DistanceFormatter.Type + private let altitudeFormatter: AltitudeFormatter.Type + private let unitSystemMultiplier: CGFloat + private let altitudeStep: CGFloat + private let units: Units + + init(units: Units = Settings.measurementUnits()) { + self.units = units + self.distanceFormatter = DistanceFormatter.self + self.altitudeFormatter = AltitudeFormatter.self + switch units { + case .metric: + self.altitudeStep = Constants.metricAltitudeStep + self.unitSystemMultiplier = 1 + case .imperial: + self.altitudeStep = Constants.imperialAltitudeStep + self.unitSystemMultiplier = Constants.metricToImperialMultiplier + @unknown default: + fatalError("Unsupported units") + } + } +} + +extension ElevationProfileFormatter: ChartFormatter { + func xAxisString(from value: Double) -> String { + distanceFormatter.distanceString(fromMeters: value) + } + + func yAxisString(from value: Double) -> String { + altitudeFormatter.altitudeString(fromMeters: value) + } + + func yAxisLowerBound(from value: CGFloat) -> CGFloat { + floor((value / unitSystemMultiplier) / altitudeStep) * altitudeStep * unitSystemMultiplier + } + + func yAxisUpperBound(from value: CGFloat) -> CGFloat { + ceil((value / unitSystemMultiplier) / altitudeStep) * altitudeStep * unitSystemMultiplier + } + + func yAxisSteps(lowerBound: CGFloat, upperBound: CGFloat) -> [CGFloat] { + let lower = yAxisLowerBound(from: lowerBound) + let upper = yAxisUpperBound(from: upperBound) + let range = upper - lower + var stepSize = altitudeStep + var stepsCount = Int((range / stepSize).rounded(.up)) + + while stepsCount > 6 { + stepSize *= 2 // Double the step size to reduce the step count + stepsCount = Int((range / stepSize).rounded(.up)) + } + + let steps = stride(from: lower, through: upper, by: stepSize) + return Array(steps) + } +} diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfilePresenter.swift b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfilePresenter.swift index c9723a961b..0a0f6d3c7f 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfilePresenter.swift +++ b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfilePresenter.swift @@ -1,4 +1,5 @@ import Chart +import CoreApi protocol ElevationProfilePresenterProtocol: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func configure() @@ -9,7 +10,7 @@ protocol ElevationProfilePresenterProtocol: UICollectionViewDataSource, UICollec protocol ElevationProfileViewControllerDelegate: AnyObject { func openDifficultyPopup() - func updateMapPoint(_ distance: Double) + func updateMapPoint(_ point: CLLocationCoordinate2D, distance: Double) } fileprivate struct DescriptionsViewModel { @@ -18,31 +19,38 @@ fileprivate struct DescriptionsViewModel { let imageName: String } -class ElevationProfilePresenter: NSObject { +final class ElevationProfilePresenter: NSObject { private weak var view: ElevationProfileViewProtocol? - private let data: ElevationProfileData + private let trackInfo: TrackRecordingInfo + private let profileData: ElevationProfileData? private let delegate: ElevationProfileViewControllerDelegate? private let cellSpacing: CGFloat = 8 private let descriptionModels: [DescriptionsViewModel] - private let chartData: ElevationProfileChartData - private let formatter: ChartFormatter + private let chartData: ElevationProfileChartData? + private let formatter: ElevationProfileFormatter init(view: ElevationProfileViewProtocol, - data: ElevationProfileData, - imperialUnits: Bool, + trackInfo: TrackRecordingInfo, + profileData: ElevationProfileData?, + formatter: ElevationProfileFormatter = ElevationProfileFormatter(), delegate: ElevationProfileViewControllerDelegate?) { self.view = view - self.data = data + self.trackInfo = trackInfo + self.profileData = profileData self.delegate = delegate - chartData = ElevationProfileChartData(data) - formatter = ChartFormatter(imperial: imperialUnits) + if let profileData { + self.chartData = ElevationProfileChartData(profileData) + } else { + self.chartData = nil + } + self.formatter = formatter descriptionModels = [ - DescriptionsViewModel(title: L("elevation_profile_ascent"), value: data.ascent, imageName: "ic_em_ascent_24"), - DescriptionsViewModel(title: L("elevation_profile_descent"), value: data.descent, imageName: "ic_em_descent_24"), - DescriptionsViewModel(title: L("elevation_profile_max_elevation"), value: data.maxAttitude, imageName: "ic_em_max_attitude_24"), - DescriptionsViewModel(title: L("elevation_profile_min_elevation"), value: data.minAttitude, imageName: "ic_em_min_attitude_24") + DescriptionsViewModel(title: L("elevation_profile_ascent"), value: trackInfo.ascent, imageName: "ic_em_ascent_24"), + DescriptionsViewModel(title: L("elevation_profile_descent"), value: trackInfo.descent, imageName: "ic_em_descent_24"), + DescriptionsViewModel(title: L("elevation_profile_max_elevation"), value: trackInfo.maxElevation, imageName: "ic_em_max_attitude_24"), + DescriptionsViewModel(title: L("elevation_profile_min_elevation"), value: trackInfo.minElevation, imageName: "ic_em_min_attitude_24") ] } @@ -54,35 +62,34 @@ class ElevationProfilePresenter: NSObject { extension ElevationProfilePresenter: ElevationProfilePresenterProtocol { func configure() { - if data.difficulty != .disabled { + guard let profileData, let chartData else { + view?.isChartViewHidden = true + view?.isDifficultyHidden = true + view?.isExtendedDifficultyLabelHidden = true + view?.isBottomPanelHidden = true + return + } + view?.isChartViewHidden = false + + if profileData.difficulty != .disabled { view?.isDifficultyHidden = false - view?.setDifficulty(data.difficulty) + view?.setDifficulty(profileData.difficulty) } else { view?.isDifficultyHidden = true } - if data.trackTime != 0 { - let eta = DurationFormatter.durationString(from: TimeInterval(data.trackTime)) - view?.isTimeHidden = false - view?.setTrackTime("\(eta)") - } else { - view?.isTimeHidden = true - } - - view?.isBottomPanelHidden = data.trackTime == 0 && data.difficulty == .disabled + view?.isBottomPanelHidden = profileData.difficulty == .disabled view?.isExtendedDifficultyLabelHidden = true - let presentationData = ChartPresentationData(chartData, - formatter: formatter, - useFilter: true) + let presentationData = ChartPresentationData(chartData, formatter: formatter) view?.setChartData(presentationData) - view?.setActivePoint(data.activePoint) - view?.setMyPosition(data.myPosition) + view?.setActivePoint(profileData.activePoint) + view?.setMyPosition(profileData.myPosition) - BookmarksManager.shared().setElevationActivePointChanged(data.trackId) { [weak self] distance in + BookmarksManager.shared().setElevationActivePointChanged(profileData.trackId) { [weak self] distance in self?.view?.setActivePoint(distance) } - BookmarksManager.shared().setElevationMyPositionChanged(data.trackId) { [weak self] distance in + BookmarksManager.shared().setElevationMyPositionChanged(profileData.trackId) { [weak self] distance in self?.view?.setMyPosition(distance) } } @@ -92,13 +99,10 @@ extension ElevationProfilePresenter: ElevationProfilePresenterProtocol { } func onSelectedPointChanged(_ point: CGFloat) { - let x1 = Int(floor(point)) - let x2 = Int(ceil(point)) - let d1: Double = chartData.points[x1].distance - let d2: Double = chartData.points[x2].distance - let dx = Double(point.truncatingRemainder(dividingBy: 1)) - let distance = d1 + (d2 - d1) * dx - delegate?.updateMapPoint(distance) + guard let chartData else { return } + let distance: Double = floor(point) / CGFloat(chartData.points.count) * chartData.maxDistance + let point = chartData.points.first { $0.distance >= distance } ?? chartData.points[0] + delegate?.updateMapPoint(point.coordinates, distance: point.distance) } } @@ -112,7 +116,7 @@ extension ElevationProfilePresenter { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ElevationProfileDescriptionCell", for: indexPath) as! ElevationProfileDescriptionCell let model = descriptionModels[indexPath.row] - cell.configure(title: model.title, value: formatter.altitudeString(from: Double(model.value)), imageName: model.imageName) + cell.configure(title: model.title, value: formatter.yAxisString(from: Double(model.value)), imageName: model.imageName) return cell } } @@ -134,61 +138,32 @@ extension ElevationProfilePresenter { } fileprivate struct ElevationProfileChartData { - struct Line: IChartLine { - var values: [Int] + + struct Line: ChartLine { + var values: [ChartValue] var name: String var color: UIColor var type: ChartLineType } + fileprivate let chartValues: [ChartValue] fileprivate let chartLines: [Line] fileprivate let distances: [Double] + fileprivate let maxDistance: Double fileprivate let points: [ElevationHeightPoint] init(_ elevationData: ElevationProfileData) { - points = ElevationProfileChartData.rearrangePoints(elevationData.points) - let values = points.map { Int($0.altitude) } - distances = points.map { $0.distance } - let color = UIColor(red: 0.12, green: 0.59, blue: 0.94, alpha: 1) - let lineColor = StyleManager.shared.theme?.colors.chartLine ?? color - let lineShadowColor = StyleManager.shared.theme?.colors.chartShadow ?? color.withAlphaComponent(0.12) - let l1 = Line(values: values, name: "Altitude", color: lineColor, type: .line) - let l2 = Line(values: values, name: "Altitude", color: lineShadowColor, type: .lineArea) + self.points = elevationData.points + self.chartValues = points.map { ChartValue(xValues: $0.distance, y: $0.altitude) } + self.distances = points.map { $0.distance } + self.maxDistance = distances.last ?? 0 + let lineColor = StyleManager.shared.theme?.colors.chartLine ?? .blue + let lineShadowColor = StyleManager.shared.theme?.colors.chartShadow ?? .lightGray + let l1 = Line(values: chartValues, name: "Altitude", color: lineColor, type: .line) + let l2 = Line(values: chartValues, name: "Altitude", color: lineShadowColor, type: .lineArea) chartLines = [l1, l2] } - private static func rearrangePoints(_ points: [ElevationHeightPoint]) -> [ElevationHeightPoint] { - if points.isEmpty { - return [] - } - - var result: [ElevationHeightPoint] = [] - - let distance = points.last?.distance ?? 0 - let step = max(1, points.count > 50 ? floor(distance / Double(points.count)) : floor(distance / 50)) - result.append(points[0]) - var currentDistance = step - var i = 1 - while i < points.count { - let prevPoint = points[i - 1] - let nextPoint = points[i] - if currentDistance > nextPoint.distance { - i += 1 - continue - } - result.append(ElevationHeightPoint(distance: currentDistance, - andAltitude: altBetweenPoints(prevPoint, nextPoint, at: currentDistance))) - currentDistance += step - if currentDistance > nextPoint.distance { - i += 1 - } - } - - result.append(points.last!) - - return result - } - private static func altBetweenPoints(_ p1: ElevationHeightPoint, _ p2: ElevationHeightPoint, at distance: Double) -> Double { @@ -197,56 +172,10 @@ fileprivate struct ElevationProfileChartData { let d = (distance - p1.distance) / (p2.distance - p1.distance) return p1.altitude + round(Double(p2.altitude - p1.altitude) * d) } - } -extension ElevationProfileChartData: IChartData { - public var xAxisValues: [Double] { - distances - } - - public var lines: [IChartLine] { - chartLines - } - - public var type: ChartType { - .regular - } -} - -final class ChartFormatter: IFormatter { - private let distanceFormatter: MKDistanceFormatter - private let altFormatter: MeasurementFormatter - private let timeFormatter: DateComponentsFormatter - private let imperial: Bool - - init(imperial: Bool) { - self.imperial = imperial - - distanceFormatter = MKDistanceFormatter() - distanceFormatter.units = imperial ? .imperial : .metric - distanceFormatter.unitStyle = .abbreviated - - altFormatter = MeasurementFormatter() - altFormatter.unitOptions = [.providedUnit] - - timeFormatter = DateComponentsFormatter() - timeFormatter.allowedUnits = [.day, .hour, .minute] - timeFormatter.unitsStyle = .abbreviated - timeFormatter.maximumUnitCount = 2 - } - - func distanceString(from value: Double) -> String { - distanceFormatter.string(fromDistance: value) - } - - func altitudeString(from value: Double) -> String { - let alt = imperial ? value / 0.3048 : value - let measurement = Measurement(value: alt.rounded(), unit: imperial ? UnitLength.feet : UnitLength.meters) - return altFormatter.string(from: measurement) - } - - func timeString(from value: Double) -> String { - timeFormatter.string(from: value) ?? "" - } +extension ElevationProfileChartData: ChartData { + public var xAxisValues: [Double] { distances } + public var lines: [ChartLine] { chartLines } + public var type: ChartType { .regular } } diff --git a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileViewController.swift b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileViewController.swift index 45e1496aef..37d41a4f0f 100644 --- a/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/ElevationProfile/ElevationProfileViewController.swift @@ -2,13 +2,13 @@ import Chart protocol ElevationProfileViewProtocol: AnyObject { var presenter: ElevationProfilePresenterProtocol? { get set } - + + var isChartViewHidden: Bool { get set } var isExtendedDifficultyLabelHidden: Bool { get set } var isDifficultyHidden: Bool { get set } - var isTimeHidden: Bool { get set } var isBottomPanelHidden: Bool { get set } + func setExtendedDifficultyGrade(_ value: String) - func setTrackTime(_ value: String?) func setDifficulty(_ value: ElevationDifficulty) func setChartData(_ data: ChartPresentationData) func setActivePoint(_ distance: Double) @@ -16,23 +16,27 @@ protocol ElevationProfileViewProtocol: AnyObject { } class ElevationProfileViewController: UIViewController { + + private enum Constants { + static let chartViewVisibleHeight: CGFloat = 176 + static let chartViewHiddenHeight: CGFloat = 20 + static let difficultyVisibleHeight: CGFloat = 60 + static let difficultyHiddenHeight: CGFloat = 20 + } + var presenter: ElevationProfilePresenterProtocol? - @IBOutlet private var chartView: ChartView! - @IBOutlet private var graphViewContainer: UIView! - @IBOutlet private var descriptionCollectionView: UICollectionView! - @IBOutlet private var difficultyView: DifficultyView! - @IBOutlet private var difficultyTitle: UILabel! - @IBOutlet private var extendedDifficultyGradeLabel: UILabel! - @IBOutlet private var trackTimeLabel: UILabel! - @IBOutlet private var trackTimeTitle: UILabel! - @IBOutlet private var extendedGradeButton: UIButton! - @IBOutlet private var diffucultyConstraint: NSLayoutConstraint! + @IBOutlet private weak var chartView: ChartView! + @IBOutlet private weak var graphViewContainer: UIView! + @IBOutlet private weak var descriptionCollectionView: UICollectionView! + @IBOutlet private weak var difficultyView: DifficultyView! + @IBOutlet private weak var difficultyTitle: UILabel! + @IBOutlet private weak var extendedDifficultyGradeLabel: UILabel! + @IBOutlet private weak var extendedGradeButton: UIButton! + @IBOutlet private weak var chartHeightConstraint: NSLayoutConstraint! + @IBOutlet private weak var difficultyConstraint: NSLayoutConstraint! - private let diffucultiVisibleConstraint: CGFloat = 60 - private let diffucultyHiddenConstraint: CGFloat = 10 private var difficultyHidden: Bool = false - private var timeHidden: Bool = false private var bottomPanelHidden: Bool = false override func viewDidLoad() { @@ -60,6 +64,15 @@ class ElevationProfileViewController: UIViewController { } extension ElevationProfileViewController: ElevationProfileViewProtocol { + var isChartViewHidden: Bool { + get { return chartView.isHidden } + set { + chartView.isHidden = newValue + graphViewContainer.isHidden = newValue + chartHeightConstraint.constant = newValue ? Constants.chartViewHiddenHeight : Constants.chartViewVisibleHeight + } + } + var isExtendedDifficultyLabelHidden: Bool { get { return extendedDifficultyGradeLabel.isHidden } set { @@ -77,25 +90,15 @@ extension ElevationProfileViewController: ElevationProfileViewProtocol { } } - var isTimeHidden: Bool { - get { timeHidden } - set { - timeHidden = newValue - trackTimeLabel.isHidden = newValue - trackTimeTitle.isHidden = newValue - } - } - var isBottomPanelHidden: Bool { get { bottomPanelHidden } set { bottomPanelHidden = newValue if newValue == true { - isTimeHidden = true isExtendedDifficultyLabelHidden = true isDifficultyHidden = true } - diffucultyConstraint.constant = newValue ? diffucultyHiddenConstraint : diffucultiVisibleConstraint + difficultyConstraint.constant = newValue ? Constants.difficultyHiddenHeight : Constants.difficultyVisibleHeight } } @@ -103,10 +106,6 @@ extension ElevationProfileViewController: ElevationProfileViewProtocol { extendedDifficultyGradeLabel.text = value } - func setTrackTime(_ value: String?) { - trackTimeLabel.text = value - } - func setDifficulty(_ value: ElevationDifficulty) { difficultyView.difficulty = value } diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePageBookmarkViewController.swift b/iphone/Maps/UI/PlacePage/Components/PlacePageBookmarkViewController.swift index 6983ebd1ae..2a0bb9af7a 100644 --- a/iphone/Maps/UI/PlacePage/Components/PlacePageBookmarkViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/PlacePageBookmarkViewController.swift @@ -1,8 +1,14 @@ protocol PlacePageBookmarkViewControllerDelegate: AnyObject { func bookmarkDidPressEdit() + func trackDidPressEdit() } -class PlacePageBookmarkViewController: UIViewController { +final class PlacePageBookmarkViewController: UIViewController { + enum BookmarkData { + case bookmark(PlacePageBookmarkData) + case track(PlacePageTrackData) + } + @IBOutlet var stackView: UIStackView! @IBOutlet var spinner: UIImageView! @IBOutlet var editButton: UIButton! @@ -17,7 +23,7 @@ class PlacePageBookmarkViewController: UIViewController { } } - var bookmarkData: PlacePageBookmarkData? { + var bookmarkData: BookmarkData? { didSet { updateViews() } @@ -30,17 +36,25 @@ class PlacePageBookmarkViewController: UIViewController { } func updateViews() { - guard let bookmarkData = bookmarkData else { return } + guard let bookmarkData else { return } editButton.isEnabled = true - if let description = bookmarkData.bookmarkDescription { - if bookmarkData.isHtmlDescription { - setHtmlDescription(description) - topConstraint.constant = 16 + switch bookmarkData { + case .bookmark(let bookmark): + editButton.setTitle(L("placepage_edit_bookmark_button"), for: .normal) + if let description = bookmark.bookmarkDescription { + if bookmark.isHtmlDescription { + setHtmlDescription(description) + topConstraint.constant = 16 + } else { + expandableLabel.text = description + topConstraint.constant = description.count > 0 ? 16 : 0 + } } else { - expandableLabel.text = description - topConstraint.constant = description.count > 0 ? 16 : 0 + topConstraint.constant = 0 } - } else { + case .track: + editButton.setTitle(L("edit_track"), for: .normal) + expandableLabel.isHidden = true topConstraint.constant = 0 } } @@ -86,7 +100,13 @@ class PlacePageBookmarkViewController: UIViewController { } @IBAction func onEdit(_ sender: UIButton) { - delegate?.bookmarkDidPressEdit() + guard let bookmarkData else { return } + switch bookmarkData { + case .bookmark: + delegate?.bookmarkDidPressEdit() + case .track: + delegate?.trackDidPressEdit() + } } override func applyTheme() { diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderPresenter.swift b/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderPresenter.swift index ede407ce53..60c59c123b 100644 --- a/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderPresenter.swift +++ b/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderPresenter.swift @@ -44,6 +44,8 @@ extension PlacePageHeaderPresenter: PlacePageHeaderPresenterProtocol { view?.isExpandViewHidden = true view?.isShadowViewHidden = false } + // TODO: (KK) Enable share button for the tracks to share the whole track gpx/kml + view?.isShareButtonHidden = placePagePreviewData.coordinates == nil } func onClosePress() { diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderViewController.swift b/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderViewController.swift index 5ad6e2712e..94069e1c7c 100644 --- a/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/PlacePageHeader/PlacePageHeaderViewController.swift @@ -2,6 +2,7 @@ protocol PlacePageHeaderViewProtocol: AnyObject { var presenter: PlacePageHeaderPresenterProtocol? { get set } var isExpandViewHidden: Bool { get set } var isShadowViewHidden: Bool { get set } + var isShareButtonHidden: Bool { get set } func setTitle(_ title: String?, secondaryTitle: String?) } @@ -72,6 +73,15 @@ extension PlacePageHeaderViewController: PlacePageHeaderViewProtocol { } } + var isShareButtonHidden: Bool { + get { + shareButton.isHidden + } + set { + shareButton.isHidden = newValue + } + } + func setTitle(_ title: String?, secondaryTitle: String?) { titleText = title secondaryText = secondaryTitle diff --git a/iphone/Maps/UI/PlacePage/Components/PlacePagePreviewViewController.swift b/iphone/Maps/UI/PlacePage/Components/PlacePagePreviewViewController.swift index df19850eab..beb3a23348 100644 --- a/iphone/Maps/UI/PlacePage/Components/PlacePagePreviewViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/PlacePagePreviewViewController.swift @@ -67,7 +67,7 @@ final class PlacePagePreviewViewController: UIViewController { updateViews() } - private func updateViews() { + func updateViews() { if placePagePreviewData.isMyPosition { if let speedAndAltitude = speedAndAltitude { subtitleLabel.text = speedAndAltitude @@ -91,7 +91,7 @@ final class PlacePagePreviewViewController: UIViewController { placePageDirectionView = subtitleDirectionView - if let address = placePagePreviewData.address { + if let address = placePagePreviewData.secondarySubtitle { addressLabel.text = address placePageDirectionView = addressDirectionView } else { @@ -149,6 +149,8 @@ final class PlacePagePreviewViewController: UIViewController { } switch placePagePreviewData.schedule.state { + case .unknown: + scheduleContainerView.isHidden = true case .allDay: setScheduleLabel(state: L("twentyfour_seven"), stateColor: UIColor.systemGreen, @@ -213,9 +215,6 @@ final class PlacePagePreviewViewController: UIViewController { stateColor: UIColor.systemRed, details: details) - case .unknown: - scheduleContainerView.isHidden = true - @unknown default: fatalError() } diff --git a/iphone/Maps/UI/PlacePage/PlacePage.storyboard b/iphone/Maps/UI/PlacePage/PlacePage.storyboard index a9980cd36c..70112a29a7 100644 --- a/iphone/Maps/UI/PlacePage/PlacePage.storyboard +++ b/iphone/Maps/UI/PlacePage/PlacePage.storyboard @@ -1,9 +1,9 @@ - + - + @@ -545,7 +545,7 @@ diff --git a/iphone/Maps/UI/PlacePage/PlacePageBuilder.swift b/iphone/Maps/UI/PlacePage/PlacePageBuilder.swift index d3f6abc0f3..0f7795f5d3 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageBuilder.swift +++ b/iphone/Maps/UI/PlacePage/PlacePageBuilder.swift @@ -1,19 +1,24 @@ @objc class PlacePageBuilder: NSObject { - @objc static func build() -> PlacePageViewController { + @objc static func build(for data: PlacePageData) -> PlacePageViewController { let storyboard = UIStoryboard.instance(.placePage) guard let viewController = storyboard.instantiateInitialViewController() as? PlacePageViewController else { fatalError() } - let data = PlacePageData(localizationProvider: OpeinigHoursLocalization()) viewController.isPreviewPlus = data.isPreviewPlus let interactor = PlacePageInteractor(viewController: viewController, data: data, mapViewController: MapViewController.shared()!) let layout: IPlacePageLayout - if data.isTrack { - layout = PlacePageElevationLayout(interactor: interactor, storyboard: storyboard, data: data) - } else { + switch data.objectType { + case .POI, .bookmark: layout = PlacePageCommonLayout(interactor: interactor, storyboard: storyboard, data: data) + case .track: + layout = PlacePageTrackLayout(interactor: interactor, storyboard: storyboard, data: data) + case .trackRecording: + // TODO: Implement PlacePageTrackRecordingLayout + fatalError("PlacePageTrackRecordingLayout is not implemented") + @unknown default: + fatalError() } let presenter = PlacePagePresenter(view: viewController) viewController.setLayout(layout) @@ -23,17 +28,22 @@ return viewController } - @objc static func update(_ viewController: PlacePageViewController) { - let data = PlacePageData(localizationProvider: OpeinigHoursLocalization()) + @objc static func update(_ viewController: PlacePageViewController, with data: PlacePageData) { viewController.isPreviewPlus = data.isPreviewPlus let interactor = PlacePageInteractor(viewController: viewController, data: data, mapViewController: MapViewController.shared()!) let layout: IPlacePageLayout - if data.isTrack { - layout = PlacePageElevationLayout(interactor: interactor, storyboard: viewController.storyboard!, data: data) - } else { + switch data.objectType { + case .POI, .bookmark: layout = PlacePageCommonLayout(interactor: interactor, storyboard: viewController.storyboard!, data: data) + case .track: + layout = PlacePageTrackLayout(interactor: interactor, storyboard: viewController.storyboard!, data: data) + case .trackRecording: + // TODO: Implement PlacePageTrackRecordingLayout + fatalError("PlacePageTrackRecordingLayout is not implemented") + @unknown default: + fatalError() } let presenter = PlacePagePresenter(view: viewController) viewController.interactor = interactor diff --git a/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift b/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift index 03e2648708..27e3da7e77 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift +++ b/iphone/Maps/UI/PlacePage/PlacePageInteractor.swift @@ -23,19 +23,15 @@ class PlacePageInteractor: NSObject { removeFromBookmarksManagerObserverList() } - private func updateBookmarkIfNeeded() { - if placePageData.isTrack { - guard let trackId = placePageData.trackData?.trackId, bookmarksManager.hasTrack(trackId) else { - presenter?.closeAnimated() - return - } - } else { - guard let bookmarkId = placePageData.bookmarkData?.bookmarkId, bookmarksManager.hasBookmark(bookmarkId) else { - return - } - FrameworkHelper.updatePlacePageData() - placePageData.updateBookmarkStatus() + private func updatePlacePageIfNeeded() { + let isBookmark = placePageData.bookmarkData != nil && bookmarksManager.hasBookmark(placePageData.bookmarkData!.bookmarkId) + let isTrack = placePageData.trackData != nil && bookmarksManager.hasTrack(placePageData.trackData!.trackId) + guard isBookmark || isTrack else { + presenter?.closeAnimated() + return } + FrameworkHelper.updatePlacePageData() + placePageData.updateBookmarkStatus() } private func addToBookmarksManagerObserverList() { @@ -54,7 +50,7 @@ extension PlacePageInteractor: PlacePageInteractorProtocol { viewWillAppearIsCalledForTheFirstTime = true return } - updateBookmarkIfNeeded() + updatePlacePageIfNeeded() } func updateTopBound(_ bound: CGFloat, duration: TimeInterval) { @@ -284,7 +280,7 @@ extension PlacePageInteractor: PlacePageHeaderViewControllerDelegate { // MARK: - BookmarksObserver extension PlacePageInteractor: BookmarksObserver { func onBookmarksLoadFinished() { - updateBookmarkIfNeeded() + updatePlacePageIfNeeded() } func onBookmarksCategoryDeleted(_ groupId: MWMMarkGroupID) { diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h index 0263b96164..a82a84c698 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h @@ -2,6 +2,7 @@ typedef NS_ENUM(NSInteger, MWMActionBarButtonType) { MWMActionBarButtonTypeBooking, MWMActionBarButtonTypeBookingSearch, MWMActionBarButtonTypeBookmark, + MWMActionBarButtonTypeTrack, MWMActionBarButtonTypeCall, MWMActionBarButtonTypeDownload, MWMActionBarButtonTypeMore, diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m index e5f64f85d3..0a7401bafa 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m @@ -17,6 +17,7 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) { case MWMActionBarButtonTypeCall: return L(@"placepage_call_button"); case MWMActionBarButtonTypeBookmark: + case MWMActionBarButtonTypeTrack: return L(isSelected ? @"delete" : @"save"); case MWMActionBarButtonTypeRouteFrom: return L(@"p2p_from_here"); @@ -103,6 +104,10 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) { case MWMActionBarButtonTypeBookmark: [self setupBookmarkButton:isSelected]; break; + case MWMActionBarButtonTypeTrack: + [self.button setImage:[[UIImage imageNamed:@"ic_route_manager_trash"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; + self.button.coloring = MWMButtonColoringRed; + break; case MWMActionBarButtonTypeRouteFrom: [self.button setImage:[UIImage imageNamed:@"ic_route_from"] forState:UIControlStateNormal]; break; diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageCommonLayout.swift b/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageCommonLayout.swift index f71abcb560..10758c7877 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageCommonLayout.swift +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageCommonLayout.swift @@ -103,7 +103,7 @@ class PlacePageCommonLayout: NSObject, IPlacePageLayout { viewControllers.append(bookmarkViewController) if let bookmarkData = placePageData.bookmarkData { - bookmarkViewController.bookmarkData = bookmarkData + bookmarkViewController.bookmarkData = .bookmark(bookmarkData) bookmarkViewController.view.isHidden = false } @@ -183,7 +183,7 @@ extension PlacePageCommonLayout { func updateBookmarkRelatedSections() { var isBookmark = false if let bookmarkData = placePageData.bookmarkData { - bookmarkViewController.bookmarkData = bookmarkData + bookmarkViewController.bookmarkData = .bookmark(bookmarkData) isBookmark = true } if let title = placePageData.previewData.title, let headerViewController = headerViewControllers.compactMap({ $0 as? PlacePageHeaderViewController }).first { diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageElevationLayout.swift b/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageElevationLayout.swift deleted file mode 100644 index 3b49316114..0000000000 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageElevationLayout.swift +++ /dev/null @@ -1,57 +0,0 @@ -class PlacePageElevationLayout: IPlacePageLayout { - private var placePageData: PlacePageData - private var interactor: PlacePageInteractor - private let storyboard: UIStoryboard - weak var presenter: PlacePagePresenterProtocol? - - lazy var bodyViewControllers: [UIViewController] = { - return configureViewControllers() - }() - - var actionBar: ActionBarViewController? = nil - - var navigationBar: UIViewController? { - return placePageNavigationViewController - } - - lazy var headerViewControllers: [UIViewController] = { - return [PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .flexible)] - } () - - lazy var placePageNavigationViewController: PlacePageHeaderViewController = { - return PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .fixed) - } () - - lazy var elevationMapViewController: ElevationProfileViewController = { - let vc = ElevationProfileBuilder.build(data: placePageData, delegate: interactor) - return vc - } () - - init(interactor: PlacePageInteractor, storyboard: UIStoryboard, data: PlacePageData) { - self.interactor = interactor - self.storyboard = storyboard - self.placePageData = data - } - - private func configureViewControllers() -> [UIViewController] { - var viewControllers = [UIViewController]() - viewControllers.append(elevationMapViewController) - - return viewControllers - } - - func calculateSteps(inScrollView scrollView: UIScrollView, compact: Bool) -> [PlacePageState] { - var steps: [PlacePageState] = [] - let scrollHeight = scrollView.height - let previewHeight = elevationMapViewController.getPreviewHeight() - steps.append(.closed(-scrollHeight)) - guard let previewView = elevationMapViewController.view else { - return steps - } - let previewFrame = scrollView.convert(previewView.bounds, from: previewView) - steps.append(.preview(previewFrame.maxY - scrollHeight - previewHeight)) - steps.append(.expanded(previewFrame.maxY - scrollHeight)) - steps.append(.full(0)) - return steps - } -} diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageTrackLayout.swift b/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageTrackLayout.swift new file mode 100644 index 0000000000..05ad51dcfd --- /dev/null +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/Layouts/PlacePageTrackLayout.swift @@ -0,0 +1,129 @@ +class PlacePageTrackLayout: IPlacePageLayout { + private var placePageData: PlacePageData + private var interactor: PlacePageInteractor + private let storyboard: UIStoryboard + weak var presenter: PlacePagePresenterProtocol? + + lazy var bodyViewControllers: [UIViewController] = { + return configureViewControllers() + }() + + var actionBar: ActionBarViewController? { + actionBarViewController + } + + var navigationBar: UIViewController? { + placePageNavigationViewController + } + + lazy var headerViewControllers: [UIViewController] = { + [headerViewController, previewViewController] + }() + + lazy var headerViewController: PlacePageHeaderViewController = { + PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .flexible) + }() + + lazy var previewViewController: PlacePagePreviewViewController = { + let vc = storyboard.instantiateViewController(ofType: PlacePagePreviewViewController.self) + vc.placePagePreviewData = placePageData.previewData + return vc + }() + + lazy var placePageNavigationViewController: PlacePageHeaderViewController = { + return PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .fixed) + }() + + lazy var bookmarkViewController: PlacePageBookmarkViewController = { + let vc = storyboard.instantiateViewController(ofType: PlacePageBookmarkViewController.self) + vc.view.isHidden = true + vc.delegate = interactor + return vc + }() + + lazy var elevationMapViewController: ElevationProfileViewController? = { + guard let trackData = placePageData.trackData else { + return nil + } + return ElevationProfileBuilder.build(trackInfo: trackData.trackInfo, + elevationProfileData: trackData.elevationProfileData, + delegate: interactor) + }() + + lazy var actionBarViewController: ActionBarViewController = { + let vc = storyboard.instantiateViewController(ofType: ActionBarViewController.self) + vc.placePageData = placePageData + vc.canAddStop = MWMRouter.canAddIntermediatePoint() + vc.isRoutePlanning = MWMNavigationDashboardManager.shared().state != .hidden + vc.delegate = interactor + return vc + }() + + init(interactor: PlacePageInteractor, storyboard: UIStoryboard, data: PlacePageData) { + self.interactor = interactor + self.storyboard = storyboard + self.placePageData = data + } + + private func configureViewControllers() -> [UIViewController] { + var viewControllers = [UIViewController]() + + viewControllers.append(bookmarkViewController) + if let trackData = placePageData.trackData { + bookmarkViewController.bookmarkData = .track(trackData) + bookmarkViewController.view.isHidden = false + } + + placePageData.onBookmarkStatusUpdate = { [weak self] in + guard let self = self else { return } + self.previewViewController.placePagePreviewData = self.placePageData.previewData + self.updateTrackRelatedSections() + } + + if let elevationMapViewController { + viewControllers.append(elevationMapViewController) + } + + return viewControllers + } + + func calculateSteps(inScrollView scrollView: UIScrollView, compact: Bool) -> [PlacePageState] { + var steps: [PlacePageState] = [] + let scrollHeight = scrollView.height + steps.append(.closed(-scrollHeight)) + guard elevationMapViewController != nil else { + steps.append(.full(0)) + return steps + } + guard let previewView = previewViewController.view else { + return steps + } + let previewFrame = scrollView.convert(previewView.bounds, from: previewView) + steps.append(.preview(previewFrame.maxY - scrollHeight)) + if !compact { + steps.append(.expanded(-scrollHeight * 0.55)) + } + steps.append(.full(0)) + return steps + } +} + +private extension PlacePageTrackLayout { + func updateTrackRelatedSections() { + guard let trackData = placePageData.trackData else { + presenter?.closeAnimated() + return + } + bookmarkViewController.bookmarkData = .track(trackData) + let previewData = placePageData.previewData + if let headerViewController = headerViewControllers.compactMap({ $0 as? PlacePageHeaderViewController }).first { + headerViewController.setTitle(previewData.title, secondaryTitle: previewData.secondaryTitle) + placePageNavigationViewController.setTitle(previewData.title, secondaryTitle: previewData.secondaryTitle) + } + if let previewViewController = headerViewControllers.compactMap({ $0 as? PlacePagePreviewViewController }).first { + previewViewController.placePagePreviewData = previewData + previewViewController.updateViews() + } + presenter?.layoutIfNeeded() + } +} diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm index 982c61a18a..dbaaac446b 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm +++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManager.mm @@ -87,8 +87,8 @@ using namespace storage; NSString *title = nil; if (data.previewData.title.length > 0) { title = data.previewData.title; - } else if (data.previewData.address.length > 0) { - title = data.previewData.address; + } else if (data.previewData.secondarySubtitle.length > 0) { + title = data.previewData.secondarySubtitle; } else if (data.previewData.subtitle.length > 0) { title = data.previewData.subtitle; } else if (data.bookmarkData != nil) { @@ -121,8 +121,8 @@ using namespace storage; NSString *title = nil; if (data.previewData.title.length > 0) { title = data.previewData.title; - } else if (data.previewData.address.length > 0) { - title = data.previewData.address; + } else if (data.previewData.secondarySubtitle.length > 0) { + title = data.previewData.secondarySubtitle; } else if (data.previewData.subtitle.length > 0) { title = data.previewData.subtitle; } else if (data.bookmarkData != nil) { @@ -185,12 +185,16 @@ using namespace storage; { auto &f = GetFramework(); f.GetBookmarkManager().GetEditSession().DeleteBookmark(data.bookmarkData.bookmarkId); - [MWMFrameworkHelper updateAfterDeleteBookmark]; - [data updateBookmarkStatus]; } +- (void)removeTrack:(PlacePageData *)data +{ + auto &f = GetFramework(); + f.GetBookmarkManager().GetEditSession().DeleteTrack(data.trackData.trackId); +} + - (void)call:(PlacePageData *)data { if (data.infoData.phoneUrl && [UIApplication.sharedApplication canOpenURL:data.infoData.phoneUrl]) { [UIApplication.sharedApplication openURL:data.infoData.phoneUrl options:@{} completionHandler:nil]; @@ -204,6 +208,20 @@ using namespace storage; [[MapViewController sharedController].navigationController pushViewController:editBookmarkController animated:YES]; } +- (void)editTrack:(PlacePageData *)data { + if (data.objectType != PlacePageObjectTypeTrack) { + ASSERT_FAIL("editTrack called for non-track object"); + return; + } + EditTrackViewController * editTrackController = [[EditTrackViewController alloc] initWithTrackId:data.trackData.trackId editCompletion:^(BOOL edited) { + if (!edited) + return; + [MWMFrameworkHelper updatePlacePageData]; + [data updateBookmarkStatus]; + }]; + [[MapViewController sharedController].navigationController pushViewController:editTrackController animated:YES]; +} + - (void)showPlaceDescription:(NSString *)htmlString { [self.ownerViewController openFullPlaceDescriptionWithHtml:htmlString]; diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h index 0b7efa3c19..e5a1c78617 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h +++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.h @@ -28,7 +28,9 @@ + (void)openCatalogMoreItems:(PlacePageData *)data; + (void)addBookmark:(PlacePageData *)data; + (void)removeBookmark:(PlacePageData *)data; ++ (void)removeTrack:(PlacePageData *)data; + (void)editBookmark:(PlacePageData *)data; ++ (void)editTrack:(PlacePageData *)data; + (void)searchBookingHotels:(PlacePageData *)data; + (void)book:(PlacePageData *)data; + (void)routeFrom:(PlacePageData *)data; diff --git a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm index f6b78cdd17..4feae30af8 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm +++ b/iphone/Maps/UI/PlacePage/PlacePageManager/MWMPlacePageManagerHelper.mm @@ -35,7 +35,9 @@ - (void)openCatalogMoreItems:(PlacePageData *)data; - (void)addBookmark:(PlacePageData *)data; - (void)removeBookmark:(PlacePageData *)data; +- (void)removeTrack:(PlacePageData *)data; - (void)editBookmark:(PlacePageData *)data; +- (void)editTrack:(PlacePageData *)data; - (void)searchBookingHotels:(PlacePageData *)data; - (void)book:(PlacePageData *)data; - (void)routeFrom:(PlacePageData *)data; @@ -152,10 +154,18 @@ [[MWMMapViewControlsManager manager].placePageManager removeBookmark:data]; } ++ (void)removeTrack:(PlacePageData *)data { + [[MWMMapViewControlsManager manager].placePageManager removeTrack:data]; +} + + (void)editBookmark:(PlacePageData *)data { [[MWMMapViewControlsManager manager].placePageManager editBookmark:data]; } ++ (void)editTrack:(PlacePageData *)data { + [[MWMMapViewControlsManager manager].placePageManager editTrack:data]; +} + + (void)searchBookingHotels:(PlacePageData *)data { [[MWMMapViewControlsManager manager].placePageManager searchBookingHotels:data]; } diff --git a/iphone/Maps/UI/PlacePage/Util/OpeinigHoursLocalization.swift b/iphone/Maps/UI/PlacePage/Util/OpeinigHoursLocalization.swift index bf107300ce..dab1a5a463 100644 --- a/iphone/Maps/UI/PlacePage/Util/OpeinigHoursLocalization.swift +++ b/iphone/Maps/UI/PlacePage/Util/OpeinigHoursLocalization.swift @@ -1,6 +1,7 @@ import Foundation -class OpeinigHoursLocalization: IOpeningHoursLocalization { +@objcMembers +class OpeinigHoursLocalization: NSObject, IOpeningHoursLocalization { var closedString: String { L("closed") }