From d52ddd77f90c458d8244b4eaaf397064999007d5 Mon Sep 17 00:00:00 2001 From: Kiryl Kaveryn Date: Sat, 4 Jan 2025 14:04:10 +0400 Subject: [PATCH 1/3] [ios] enable swift/cpp interop Signed-off-by: Kiryl Kaveryn --- iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj | 2 ++ iphone/Maps/Maps.xcodeproj/project.pbxproj | 2 ++ map/module.modulemap | 10 ++++++++++ xcode/common.xcconfig | 2 +- xcode/map/map.xcodeproj/project.pbxproj | 4 ++++ 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 map/module.modulemap diff --git a/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj b/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj index 9c2620b98c..f21a2f424a 100644 --- a/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj +++ b/iphone/CoreApi/CoreApi.xcodeproj/project.pbxproj @@ -696,6 +696,7 @@ ); ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + SWIFT_OBJC_INTEROP_MODE = objcxx; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -718,6 +719,7 @@ "$(OMIM_ROOT)/3party/pugixml/pugixml/src", ); SDKROOT = iphoneos; + SWIFT_OBJC_INTEROP_MODE = objcxx; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index c2dfb5e182..391412f1f7 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -5091,6 +5091,7 @@ OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = app.organicmaps.debug; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_INTEROP_MODE = objcxx; }; name = Debug; }; @@ -5113,6 +5114,7 @@ OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = app.organicmaps; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_INTEROP_MODE = objcxx; }; name = Release; }; diff --git a/map/module.modulemap b/map/module.modulemap new file mode 100644 index 0000000000..5ee1cb03df --- /dev/null +++ b/map/module.modulemap @@ -0,0 +1,10 @@ +module map { +// header "framework.hpp" +// header "bookmark_manager.hpp" + header "bookmark.hpp" + header "track.hpp" + + header "elevation_info.hpp" + header "gps_track_collection.hpp" + export * +} diff --git a/xcode/common.xcconfig b/xcode/common.xcconfig index b3e19157c4..5811908f66 100644 --- a/xcode/common.xcconfig +++ b/xcode/common.xcconfig @@ -94,7 +94,7 @@ MTL_FAST_MATH = YES ONLY_ACTIVE_ARCH = YES PRODUCT_NAME = $(TARGET_NAME) SKIP_INSTALL = YES -SWIFT_VERSION = 5.5 +SWIFT_VERSION = 5.9 TARGETED_DEVICE_FAMILY = 1,2 VALID_ARCHS = arm64 VALID_ARCHS[sdk=iphonesimulator*] = x86_64 arm64 diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj index f5810fc704..0e63ab7b91 100644 --- a/xcode/map/map.xcodeproj/project.pbxproj +++ b/xcode/map/map.xcodeproj/project.pbxproj @@ -240,6 +240,7 @@ BBFC7E38202D29BF00531BE7 /* user_mark_layer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = user_mark_layer.cpp; sourceTree = ""; }; BBFC7E39202D29BF00531BE7 /* user_mark_layer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = user_mark_layer.hpp; sourceTree = ""; }; ED49D74B2CEF3CE3004AF27E /* elevation_info_tests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = elevation_info_tests.cpp; sourceTree = ""; }; + ED79CAC32D28259F00E63864 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; F6B282FB1C1B03320081957A /* gps_track_collection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_track_collection.cpp; sourceTree = ""; }; F6B282FC1C1B03320081957A /* gps_track_collection.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gps_track_collection.hpp; sourceTree = ""; }; F6B282FD1C1B03320081957A /* gps_track_filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_track_filter.cpp; sourceTree = ""; }; @@ -456,6 +457,7 @@ 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */, 3DA5722C20C195EC007BDE27 /* viewport_search_callback.hpp */, 3D4E99811FB462B60025B48C /* viewport_search_params.hpp */, + ED79CAC32D28259F00E63864 /* module.modulemap */, ); name = map; path = ../../map; @@ -788,6 +790,7 @@ 675345C71A4054AD00A0A8C3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + DEFINES_MODULE = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; WARNING_CFLAGS = "-Wno-deprecated-register "; @@ -797,6 +800,7 @@ 675345C81A4054AD00A0A8C3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + DEFINES_MODULE = YES; EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; WARNING_CFLAGS = "-Wno-deprecated-register "; -- 2.45.3 From 95e797cbb9309b203ea2deb6a5fb5fd954dfe5c1 Mon Sep 17 00:00:00 2001 From: Kiryl Kaveryn Date: Sat, 4 Jan 2025 14:04:49 +0400 Subject: [PATCH 2/3] [ios] fix swift 5.9 compile errors Signed-off-by: Kiryl Kaveryn --- .../Formatting/DateTimeFormatter.swift | 1 + .../Common/ProductsConfiguration.swift | 1 + .../Components/ActionBarViewController.swift | 2 +- .../ActionBar/MWMActionBarButton.h | 9 +-- .../ActionBar/MWMActionBarButton.m | 68 +++++++++---------- 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/iphone/CoreApi/CoreApi/Formatting/DateTimeFormatter.swift b/iphone/CoreApi/CoreApi/Formatting/DateTimeFormatter.swift index b165ff99a1..f9739eaa6c 100644 --- a/iphone/CoreApi/CoreApi/Formatting/DateTimeFormatter.swift +++ b/iphone/CoreApi/CoreApi/Formatting/DateTimeFormatter.swift @@ -1,4 +1,5 @@ import Foundation +import CoreLocation.CLLocation @objcMembers public final class DateTimeFormatter: NSObject { diff --git a/iphone/CoreApi/CoreApi/PlacePageData/Common/ProductsConfiguration.swift b/iphone/CoreApi/CoreApi/PlacePageData/Common/ProductsConfiguration.swift index db36f5b4d3..fe86ebe2cc 100644 --- a/iphone/CoreApi/CoreApi/PlacePageData/Common/ProductsConfiguration.swift +++ b/iphone/CoreApi/CoreApi/PlacePageData/Common/ProductsConfiguration.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit.UIGeometry @objcMembers public final class Product: NSObject { diff --git a/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift b/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift index 78bd180373..d0184d3bab 100644 --- a/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift +++ b/iphone/Maps/UI/PlacePage/Components/ActionBarViewController.swift @@ -152,7 +152,7 @@ final class ActionBarViewController: UIViewController { preferredStyle: .actionSheet) for button in additionalButtons { let (selected, enabled) = buttonState(button) - let action = UIAlertAction(title: titleForButton(button, selected), + let action = UIAlertAction(title: ActionBarButton.title(for: button, isSelected: selected), style: .default, handler: { [weak self] _ in guard let self = self else { return } diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h index a82a84c698..f87723d916 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.h @@ -24,14 +24,6 @@ typedef NS_ENUM(NSInteger, MWMBookmarksButtonState) { NS_ASSUME_NONNULL_BEGIN -#ifdef __cplusplus -extern "C" { -#endif -NSString * titleForButton(MWMActionBarButtonType type, BOOL isSelected); -#ifdef __cplusplus -} -#endif - @class MWMActionBarButton; @class MWMCircularProgress; @@ -52,6 +44,7 @@ NS_SWIFT_NAME(ActionBarButton) buttonType:(MWMActionBarButtonType)type isSelected:(BOOL)isSelected isEnabled:(BOOL)isEnabled; ++ (NSString *)titleForButton:(MWMActionBarButtonType)type isSelected:(BOOL)isSelected; - (void)setBookmarkButtonState:(MWMBookmarksButtonState)state; diff --git a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m index 0a7401bafa..1fe69f9232 100644 --- a/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m +++ b/iphone/Maps/UI/PlacePage/PlacePageLayout/ActionBar/MWMActionBarButton.m @@ -5,39 +5,6 @@ static NSString * const kUDDidHighlightRouteToButton = @"kUDDidHighlightPoint2PointButton"; -NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) { - switch (type) { - case MWMActionBarButtonTypeDownload: - return L(@"download"); - case MWMActionBarButtonTypeBooking: - case MWMActionBarButtonTypeOpentable: - return L(@"book_button"); - case MWMActionBarButtonTypeBookingSearch: - return L(@"booking_search"); - case MWMActionBarButtonTypeCall: - return L(@"placepage_call_button"); - case MWMActionBarButtonTypeBookmark: - case MWMActionBarButtonTypeTrack: - return L(isSelected ? @"delete" : @"save"); - case MWMActionBarButtonTypeRouteFrom: - return L(@"p2p_from_here"); - case MWMActionBarButtonTypeRouteTo: - return L(@"p2p_to_here"); - case MWMActionBarButtonTypeMore: - return L(@"placepage_more_button"); - case MWMActionBarButtonTypeRouteAddStop: - return L(@"placepage_add_stop"); - case MWMActionBarButtonTypeRouteRemoveStop: - return L(@"placepage_remove_stop"); - case MWMActionBarButtonTypeAvoidToll: - return L(@"avoid_tolls"); - case MWMActionBarButtonTypeAvoidDirty: - return L(@"avoid_unpaved"); - case MWMActionBarButtonTypeAvoidFerry: - return L(@"avoid_ferry"); - } -} - @interface MWMActionBarButton () @property(nonatomic) MWMActionBarButtonType type; @@ -52,7 +19,7 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) { @implementation MWMActionBarButton - (void)configButton:(BOOL)isSelected enabled:(BOOL)isEnabled { - self.label.text = titleForButton(self.type, isSelected); + self.label.text = [MWMActionBarButton titleForButton:self.type isSelected:isSelected]; self.extraBackground.hidden = YES; self.button.coloring = MWMButtonColoringBlack; @@ -221,4 +188,37 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) { return [self pointInside:point withEvent:event] ? self.button : nil; } ++ (NSString *)titleForButton:(MWMActionBarButtonType)type isSelected:(BOOL)isSelected { + switch (type) { + case MWMActionBarButtonTypeDownload: + return L(@"download"); + case MWMActionBarButtonTypeBooking: + case MWMActionBarButtonTypeOpentable: + return L(@"book_button"); + case MWMActionBarButtonTypeBookingSearch: + return L(@"booking_search"); + case MWMActionBarButtonTypeCall: + return L(@"placepage_call_button"); + case MWMActionBarButtonTypeBookmark: + case MWMActionBarButtonTypeTrack: + return L(isSelected ? @"delete" : @"save"); + case MWMActionBarButtonTypeRouteFrom: + return L(@"p2p_from_here"); + case MWMActionBarButtonTypeRouteTo: + return L(@"p2p_to_here"); + case MWMActionBarButtonTypeMore: + return L(@"placepage_more_button"); + case MWMActionBarButtonTypeRouteAddStop: + return L(@"placepage_add_stop"); + case MWMActionBarButtonTypeRouteRemoveStop: + return L(@"placepage_remove_stop"); + case MWMActionBarButtonTypeAvoidToll: + return L(@"avoid_tolls"); + case MWMActionBarButtonTypeAvoidDirty: + return L(@"avoid_unpaved"); + case MWMActionBarButtonTypeAvoidFerry: + return L(@"avoid_ferry"); + } +} + @end -- 2.45.3 From c018e8a226a083dbd7775e201b13f2fff24f7c0a Mon Sep 17 00:00:00 2001 From: Kiryl Kaveryn Date: Sat, 4 Jan 2025 21:56:38 +0400 Subject: [PATCH 3/3] [ios] attempt to implement cpp/swift inerop Signed-off-by: Kiryl Kaveryn --- .../CoreApi/Framework/MWMFrameworkHelper.h | 2 +- .../CoreApi/Framework/MWMFrameworkHelper.mm | 3 +- .../MWMMapViewControlsManager.h | 1 + .../MWMMapViewControlsManager.mm | 10 +-- iphone/Maps/Classes/Widgets/MWMMapWidgets.mm | 2 +- .../TrackRecordingActivityManager.swift | 23 +++--- .../TrackRecorder/TrackRecordingManager.swift | 70 +++++++++---------- .../Menu/BottomMenuInteractor.swift | 1 + kml/module.modulemap | 4 ++ map/framework.cpp | 16 ++--- map/framework.hpp | 2 +- map/module.modulemap | 9 +-- map/place_page_info.hpp | 2 + xcode/kml/kml.xcodeproj/project.pbxproj | 2 + xcode/map/map.xcodeproj/project.pbxproj | 8 +-- 15 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 kml/module.modulemap diff --git a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h index a81f261b43..89887d79eb 100644 --- a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h +++ b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.h @@ -18,7 +18,7 @@ typedef NS_ENUM(NSInteger, ProductsPopupCloseReason) { NS_ASSUME_NONNULL_BEGIN typedef void (^SearchInDownloaderCompletions)(NSArray *results, BOOL finished); -typedef void (^TrackRecordingUpdatedHandler)(TrackInfo * _Nonnull trackInfo); +typedef void (^TrackRecordingUpdatedHandler)(struct GpsTrackInfo trackInfo); @protocol TrackRecorder diff --git a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm index f71be86ac1..760e5e92c4 100644 --- a/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm +++ b/iphone/CoreApi/CoreApi/Framework/MWMFrameworkHelper.mm @@ -225,8 +225,7 @@ static Framework::ProductsPopupCloseReason ConvertProductPopupCloseReasonToCore( return; } GetFramework().SetTrackRecordingUpdateHandler([trackRecordingDidUpdate](GpsTrackInfo const & gpsTrackInfo) { - TrackInfo * info = [[TrackInfo alloc] initWithGpsTrackInfo:gpsTrackInfo]; - trackRecordingDidUpdate(info); + trackRecordingDidUpdate(gpsTrackInfo); }); } diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h index 1a325c25b8..296c3bb1e2 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h @@ -16,6 +16,7 @@ @property(nonatomic) BOOL zoomHidden; @property(nonatomic) BOOL sideButtonsHidden; @property(nonatomic) BOOL trafficButtonHidden; +@property(nonatomic) BOOL trackRecordingButtonHidden; @property(nonatomic) MWMBottomMenuState menuState; @property(nonatomic) MWMBottomMenuState menuRestoreState; @property(nonatomic) BOOL isDirectionViewHidden; diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm index 8944fc2075..bc76f1d780 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm @@ -64,16 +64,10 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue"; self.menuState = MWMBottomMenuStateInactive; self.menuRestoreState = MWMBottomMenuStateInactive; self.isAddingPlace = NO; - [TrackRecordingManager.shared addObserver:self recordingIsActiveDidChangeHandler:^(TrackRecordingState state, TrackInfo * trackInfo) { - [self setTrackRecordingButtonHidden:state == TrackRecordingStateInactive]; - }]; + [self setTrackRecordingButtonHidden:TrackRecordingManager.shared.recordingState == TrackRecordingStateInactive]; return self; } -- (void)dealloc { - [TrackRecordingManager.shared removeObserver:self]; -} - - (UIStatusBarStyle)preferredStatusBarStyle { BOOL const isSearchUnderStatusBar = (self.searchManager.state != MWMSearchManagerStateHidden); BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden && @@ -326,9 +320,11 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue"; [MWMMapWidgetsHelper updateLayoutForAvailableArea]; }]; _trackRecordingButton = nil; + _trackRecordingButtonHidden = true; } else if (!trackRecordingButtonHidden && !_trackRecordingButton) { _trackRecordingButton = [[TrackRecordingViewController alloc] init]; + _trackRecordingButtonHidden = false; [MWMMapWidgetsHelper updateLayoutForAvailableArea]; } } diff --git a/iphone/Maps/Classes/Widgets/MWMMapWidgets.mm b/iphone/Maps/Classes/Widgets/MWMMapWidgets.mm index 33444784d4..1511ef5b61 100644 --- a/iphone/Maps/Classes/Widgets/MWMMapWidgets.mm +++ b/iphone/Maps/Classes/Widgets/MWMMapWidgets.mm @@ -70,7 +70,7 @@ auto const viewWidth = [MapViewController sharedController].mapView.width; auto const rulerOffset = m2::PointF(frame.origin.x * vs, (frame.origin.y + frame.size.height - viewHeight) * vs); - auto const kCompassAdditionalYOffset = [TrackRecordingManager.shared isActive] ? 50 : 0; + auto const kCompassAdditionalYOffset = TrackRecordingManager.shared.recordingState == TrackRecordingStateActive ? 50 : 0; auto const compassOffset = m2::PointF((frame.origin.x + frame.size.width - viewWidth) * vs, (frame.origin.y + kCompassAdditionalYOffset) * vs); m_skin->ForEach([&](gui::EWidget w, gui::Position const & pos) { diff --git a/iphone/Maps/Core/TrackRecorder/TrackRecordingActivityManager.swift b/iphone/Maps/Core/TrackRecorder/TrackRecordingActivityManager.swift index 5df98663b4..2ab02b6446 100644 --- a/iphone/Maps/Core/TrackRecorder/TrackRecordingActivityManager.swift +++ b/iphone/Maps/Core/TrackRecorder/TrackRecordingActivityManager.swift @@ -1,10 +1,11 @@ import ActivityKit +import map #if canImport(ActivityKit) protocol TrackRecordingActivityManager { - func start(with info: TrackInfo) throws - func update(_ info: TrackInfo) + func start(with info: GpsTrackInfo) throws + func update(_ info: GpsTrackInfo) func stop() } @@ -22,7 +23,7 @@ final class TrackRecordingLiveActivityManager { @available(iOS 16.2, *) extension TrackRecordingLiveActivityManager: TrackRecordingActivityManager { - func start(with info: TrackInfo) throws { + func start(with info: GpsTrackInfo) throws { guard activity == nil else { return } let state = TrackRecordingLiveActivityAttributes.ContentState(trackInfo: info) let content = ActivityContent(state: state, staleDate: nil) @@ -30,7 +31,7 @@ extension TrackRecordingLiveActivityManager: TrackRecordingActivityManager { activity = try LiveActivityManager.startActivity(attributes, content: content) } - func update(_ info: TrackInfo) { + func update(_ info: GpsTrackInfo) { guard let activity else { return } let state = TrackRecordingLiveActivityAttributes.ContentState(trackInfo: info) let content = ActivityContent(state: state, staleDate: nil) @@ -47,13 +48,13 @@ extension TrackRecordingLiveActivityManager: TrackRecordingActivityManager { // MARK: - Wrap TrackRecordingInfo to TrackRecordingLiveActivityAttributes.ContentState private extension TrackRecordingLiveActivityAttributes.ContentState { - init(trackInfo: TrackInfo) { - let distance = DistanceFormatter.distanceString(fromMeters: trackInfo.distance) - let duration = DurationFormatter.durationString(from: trackInfo.duration) - let maxElevation = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.maxElevation)) - let minElevation = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.minElevation)) - let ascent = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.ascent)) - let descent = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.descent)) + init(trackInfo: GpsTrackInfo) { + let distance = DistanceFormatter.distanceString(fromMeters: trackInfo.m_length) + let duration = DurationFormatter.durationString(from: trackInfo.m_duration) + let maxElevation = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.m_maxElevation)) + let minElevation = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.m_minElevation)) + let ascent = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.m_ascent)) + let descent = AltitudeFormatter.altitudeString(fromMeters: Double(trackInfo.m_descent)) self.distance = StatisticsViewModel(key: "", value: distance) self.duration = StatisticsViewModel(key: "", value: duration) diff --git a/iphone/Maps/Core/TrackRecorder/TrackRecordingManager.swift b/iphone/Maps/Core/TrackRecorder/TrackRecordingManager.swift index 8e814445e7..5e02cfab29 100644 --- a/iphone/Maps/Core/TrackRecorder/TrackRecordingManager.swift +++ b/iphone/Maps/Core/TrackRecorder/TrackRecordingManager.swift @@ -1,3 +1,7 @@ +import CoreApi +import map +import kml + @objc enum TrackRecordingState: Int, Equatable { case inactive @@ -13,12 +17,15 @@ enum TrackRecordingError: Error { case locationIsProhibited } -protocol TrackRecordingObserver: AnyObject { - func addObserver(_ observer: AnyObject, recordingIsActiveDidChangeHandler: @escaping TrackRecordingStateHandler) - func removeObserver(_ observer: AnyObject) +protocol TrackRecordingObservable: AnyObject { + func addObserver(_ observer: TrackRecordingObserver) + func removeObserver(_ observer: TrackRecordingObserver) } -typealias TrackRecordingStateHandler = (TrackRecordingState, TrackInfo?) -> Void +protocol TrackRecordingObserver: AnyObject { + func trackRecordingStateDidChange(_ state: TrackRecordingState) + func trackRecordingProgressDidChange(_ trackRecordingInfo: GpsTrackInfo) +} @objcMembers final class TrackRecordingManager: NSObject { @@ -30,11 +37,6 @@ final class TrackRecordingManager: NSObject { case saveWithName(String? = nil) } - fileprivate struct Observation { - weak var observer: AnyObject? - var recordingStateDidChangeHandler: TrackRecordingStateHandler? - } - static let shared: TrackRecordingManager = { let trackRecorder = FrameworkHelper.self var activityManager: TrackRecordingActivityManager? = nil @@ -48,8 +50,8 @@ final class TrackRecordingManager: NSObject { private let trackRecorder: TrackRecorder.Type private var activityManager: TrackRecordingActivityManager? - private var observations: [Observation] = [] - private var trackRecordingInfo: TrackInfo? + private let listenerContainer = ListenerContainer() + private var trackRecordingInfo = GpsTrackInfo() var recordingState: TrackRecordingState { trackRecorder.isTrackRecordingEnabled() ? .active : .inactive @@ -60,6 +62,8 @@ final class TrackRecordingManager: NSObject { self.activityManager = activityManager super.init() subscribeOnAppLifecycleEvents() + + map.GpsTrackCollection() } // MARK: - Public methods @@ -79,11 +83,6 @@ final class TrackRecordingManager: NSObject { } } - @objc - func isActive() -> Bool { - recordingState == .active - } - func processAction(_ action: TrackRecordingAction, completion: (CompletionHandler)? = nil) { switch action { case .start: @@ -113,7 +112,7 @@ final class TrackRecordingManager: NSObject { private func willResignActive() { guard let activityManager, recordingState == .active else { return } do { - try activityManager.start(with: trackRecordingInfo ?? .empty()) + try activityManager.start(with: trackRecordingInfo) } catch { handleError(error) } @@ -135,14 +134,14 @@ final class TrackRecordingManager: NSObject { trackRecorder.setTrackRecordingUpdateHandler { [weak self] info in guard let self else { return } self.trackRecordingInfo = info - self.notifyObservers() self.activityManager?.update(info) + self.listenerContainer.forEach { $0.trackRecordingProgressDidChange(info) } } } private func unsubscribeFromTrackRecordingProgressUpdates() { trackRecorder.setTrackRecordingUpdateHandler(nil) - trackRecordingInfo = nil + trackRecordingInfo = GpsTrackInfo() } // MARK: - Handle Start/Stop event and Errors @@ -154,7 +153,10 @@ final class TrackRecordingManager: NSObject { case .inactive: subscribeOnTrackRecordingProgressUpdates() trackRecorder.startTrackRecording() - notifyObservers() + listenerContainer.forEach { + $0.trackRecordingStateDidChange(self.recordingState) + $0.trackRecordingProgressDidChange(self.trackRecordingInfo) + } case .active: break } @@ -188,8 +190,9 @@ final class TrackRecordingManager: NSObject { unsubscribeFromTrackRecordingProgressUpdates() trackRecorder.stopTrackRecording() activityManager?.stop() - notifyObservers() - + listenerContainer.forEach { + $0.trackRecordingStateDidChange(self.recordingState) + } switch savingOption { case .withoutSaving: break @@ -222,23 +225,16 @@ final class TrackRecordingManager: NSObject { } } -// MARK: - TrackRecordingObserver +// MARK: - TrackRecordingObservable -extension TrackRecordingManager: TrackRecordingObserver { - @objc - func addObserver(_ observer: AnyObject, recordingIsActiveDidChangeHandler: @escaping TrackRecordingStateHandler) { - let observation = Observation(observer: observer, recordingStateDidChangeHandler: recordingIsActiveDidChangeHandler) - observations.append(observation) - recordingIsActiveDidChangeHandler(recordingState, trackRecordingInfo) +extension TrackRecordingManager: TrackRecordingObservable { + func addObserver(_ observer: TrackRecordingObserver) { + listenerContainer.addListener(observer) + observer.trackRecordingStateDidChange(recordingState) + observer.trackRecordingProgressDidChange(trackRecordingInfo) } - @objc - func removeObserver(_ observer: AnyObject) { - observations.removeAll { $0.observer === observer } - } - - private func notifyObservers() { - observations = observations.filter { $0.observer != nil } - observations.forEach { $0.recordingStateDidChangeHandler?(recordingState, trackRecordingInfo) } + func removeObserver(_ observer: TrackRecordingObserver) { + listenerContainer.removeListener(observer) } } diff --git a/iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift b/iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift index 8457445c3c..fee3904d6e 100644 --- a/iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift +++ b/iphone/Maps/UI/BottomMenu/Menu/BottomMenuInteractor.swift @@ -81,6 +81,7 @@ extension BottomMenuInteractor: BottomMenuInteractorProtocol { func toggleTrackRecording() { trackRecorder.processAction(trackRecorder.recordingState == .active ? .stop : .start) { [weak self] in self?.close() + MWMMapViewControlsManager.manager().trackRecordingButtonHidden = false } } } diff --git a/kml/module.modulemap b/kml/module.modulemap new file mode 100644 index 0000000000..588a133e8a --- /dev/null +++ b/kml/module.modulemap @@ -0,0 +1,4 @@ +module kml { + header "types.hpp" + export * +} diff --git a/map/framework.cpp b/map/framework.cpp index 4f84c70135..21a9fb3655 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -319,10 +319,10 @@ Framework::Framework(FrameworkParams const & params, bool loadMaps) m_stringsBundle.SetDefaultString("postal_code", "Postal Code"); m_featuresFetcher.InitClassificator(); - m_featuresFetcher.SetOnMapDeregisteredCallback(bind(&Framework::OnMapDeregistered, this, _1)); + m_featuresFetcher.SetOnMapDeregisteredCallback(std::bind(&Framework::OnMapDeregistered, this, _1)); LOG(LDEBUG, ("Classificator initialized")); - m_displayedCategories = make_unique(GetDefaultCategories()); + m_displayedCategories = std::make_unique(GetDefaultCategories()); // To avoid possible races - init country info getter in constructor. InitCountryInfoGetter(); @@ -331,14 +331,14 @@ Framework::Framework(FrameworkParams const & params, bool loadMaps) InitSearchAPI(params.m_numSearchAPIThreads); LOG(LDEBUG, ("Search API initialized, part 1")); - m_bmManager = make_unique(BookmarkManager::Callbacks( + m_bmManager = std::make_unique(BookmarkManager::Callbacks( [this]() -> StringsBundle const & { return m_stringsBundle; }, [this]() -> SearchAPI & { return GetSearchAPI(); }, - [this](vector const & marks) { GetSearchAPI().OnBookmarksCreated(marks); }, - [this](vector const & marks) { GetSearchAPI().OnBookmarksUpdated(marks); }, - [this](vector const & marks) { GetSearchAPI().OnBookmarksDeleted(marks); }, - [this](vector const & marks) { GetSearchAPI().OnBookmarksAttached(marks); }, - [this](vector const & marks) { GetSearchAPI().OnBookmarksDetached(marks); })); + [this](std::vector const & marks) { GetSearchAPI().OnBookmarksCreated(marks); }, + [this](std::vector const & marks) { GetSearchAPI().OnBookmarksUpdated(marks); }, + [this](std::vector const & marks) { GetSearchAPI().OnBookmarksDeleted(marks); }, + [this](std::vector const & marks) { GetSearchAPI().OnBookmarksAttached(marks); }, + [this](std::vector const & marks) { GetSearchAPI().OnBookmarksDetached(marks); })); m_bmManager->InitRegionAddressGetter(m_featuresFetcher.GetDataSource(), *m_infoGetter); diff --git a/map/framework.hpp b/map/framework.hpp index 9fb29750aa..d3adc99d88 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -2,7 +2,7 @@ #include "map/api_mark_point.hpp" #include "map/bookmark.hpp" -#include "map/bookmark_manager.hpp" +//#include "map/bookmark_manager.hpp" #include "map/features_fetcher.hpp" #include "map/isolines_manager.hpp" #include "map/mwm_url.hpp" diff --git a/map/module.modulemap b/map/module.modulemap index 5ee1cb03df..b3a8149779 100644 --- a/map/module.modulemap +++ b/map/module.modulemap @@ -1,10 +1,11 @@ module map { // header "framework.hpp" // header "bookmark_manager.hpp" - header "bookmark.hpp" - header "track.hpp" - - header "elevation_info.hpp" header "gps_track_collection.hpp" + header "track.hpp" + header "bookmark.hpp" + header "user_mark.hpp" + header "user_mark_layer.hpp" + header "elevation_info.hpp" export * } diff --git a/map/place_page_info.hpp b/map/place_page_info.hpp index f7539b7fdb..03024d43ba 100644 --- a/map/place_page_info.hpp +++ b/map/place_page_info.hpp @@ -18,6 +18,8 @@ #include #include +class Track; + namespace place_page { enum class OpeningMode diff --git a/xcode/kml/kml.xcodeproj/project.pbxproj b/xcode/kml/kml.xcodeproj/project.pbxproj index 6327b789d8..d5a80df702 100644 --- a/xcode/kml/kml.xcodeproj/project.pbxproj +++ b/xcode/kml/kml.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ E2DC9C8C25264E0C0098174E /* types_v6.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = types_v6.hpp; sourceTree = ""; }; E2DC9C8D25264E0C0098174E /* types_v8.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = types_v8.hpp; sourceTree = ""; }; E2DC9C9025264E3E0098174E /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = ""; }; + EDCA7CC12D29AA9C003366CE /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; FA67C84A26BB365600B33DCA /* libplatform.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libplatform.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA67C84C26BB365C00B33DCA /* libbase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libbase.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA67C85026BB370C00B33DCA /* libcoding.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libcoding.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -154,6 +155,7 @@ E2DC9C9025264E3E0098174E /* types.cpp */, 45E4559420584ABA00D9F45E /* types.hpp */, 45E4559120584ABA00D9F45E /* visitors.hpp */, + EDCA7CC12D29AA9C003366CE /* module.modulemap */, ); name = kml; path = ../../kml; diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj index 0e63ab7b91..53b95fc520 100644 --- a/xcode/map/map.xcodeproj/project.pbxproj +++ b/xcode/map/map.xcodeproj/project.pbxproj @@ -57,9 +57,9 @@ 675346481A4054E800A0A8C3 /* bookmark_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675345D91A4054E800A0A8C3 /* bookmark_manager.cpp */; }; 675346491A4054E800A0A8C3 /* bookmark_manager.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675345DA1A4054E800A0A8C3 /* bookmark_manager.hpp */; }; 6753464A1A4054E800A0A8C3 /* bookmark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675345DB1A4054E800A0A8C3 /* bookmark.cpp */; }; - 6753464B1A4054E800A0A8C3 /* bookmark.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675345DC1A4054E800A0A8C3 /* bookmark.hpp */; }; + 6753464B1A4054E800A0A8C3 /* bookmark.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675345DC1A4054E800A0A8C3 /* bookmark.hpp */; settings = {ATTRIBUTES = (Public, ); }; }; 675346641A4054E800A0A8C3 /* framework.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675345F51A4054E800A0A8C3 /* framework.cpp */; }; - 675346651A4054E800A0A8C3 /* framework.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675345F61A4054E800A0A8C3 /* framework.hpp */; }; + 675346651A4054E800A0A8C3 /* framework.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675345F61A4054E800A0A8C3 /* framework.hpp */; settings = {ATTRIBUTES = (Public, ); }; }; 675346741A4054E800A0A8C3 /* mwm_url.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675346051A4054E800A0A8C3 /* mwm_url.cpp */; }; 675346751A4054E800A0A8C3 /* mwm_url.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675346061A4054E800A0A8C3 /* mwm_url.hpp */; }; 6753469B1A4054E800A0A8C3 /* track.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6753462C1A4054E800A0A8C3 /* track.cpp */; }; @@ -239,8 +239,8 @@ BBD9E2C51EE9D01900DF189A /* routing_mark.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_mark.hpp; sourceTree = ""; }; BBFC7E38202D29BF00531BE7 /* user_mark_layer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = user_mark_layer.cpp; sourceTree = ""; }; BBFC7E39202D29BF00531BE7 /* user_mark_layer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = user_mark_layer.hpp; sourceTree = ""; }; + ED2EB95B2D297E8200062C31 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; ED49D74B2CEF3CE3004AF27E /* elevation_info_tests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = elevation_info_tests.cpp; sourceTree = ""; }; - ED79CAC32D28259F00E63864 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; F6B282FB1C1B03320081957A /* gps_track_collection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_track_collection.cpp; sourceTree = ""; }; F6B282FC1C1B03320081957A /* gps_track_collection.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gps_track_collection.hpp; sourceTree = ""; }; F6B282FD1C1B03320081957A /* gps_track_filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gps_track_filter.cpp; sourceTree = ""; }; @@ -457,7 +457,7 @@ 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */, 3DA5722C20C195EC007BDE27 /* viewport_search_callback.hpp */, 3D4E99811FB462B60025B48C /* viewport_search_params.hpp */, - ED79CAC32D28259F00E63864 /* module.modulemap */, + ED2EB95B2D297E8200062C31 /* module.modulemap */, ); name = map; path = ../../map; -- 2.45.3