[ios] implement PP for the track recording

Signed-off-by: Kiryl Kaveryn <kirylkaveryn@gmail.com>
This commit is contained in:
Kiryl Kaveryn 2025-01-09 16:46:22 +04:00
parent 106507fef5
commit 29ee0da1b0
16 changed files with 193 additions and 49 deletions

View file

@ -50,6 +50,11 @@ final class TrackRecordingViewController: MWMViewController {
// MARK: - Public methods
@objc
func setHidden(_ hidden: Bool) {
button.isHidden = hidden
}
@objc
func close(completion: @escaping (() -> Void)) {
stopTimer()
@ -75,7 +80,7 @@ final class TrackRecordingViewController: MWMViewController {
button.tintColor = Constants.color.darker
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(UIImage(resource: .icMenuBookmarkTrackRecording), for: .normal)
button.addTarget(self, action: #selector(onTrackRecordingButtonPressed), for: .touchUpInside)
button.addTarget(self, action: #selector(didTap), for: .touchUpInside)
button.isHidden = true
}
@ -134,12 +139,7 @@ final class TrackRecordingViewController: MWMViewController {
// MARK: - Actions
@objc
private func onTrackRecordingButtonPressed(_ sender: Any) {
switch trackRecordingManager.recordingState {
case .inactive:
trackRecordingManager.processAction(.start)
case .active:
trackRecordingManager.processAction(.stop)
}
private func didTap(_ sender: Any) {
MapViewController.shared()?.showTrackRecordingPlacePage()
}
}

View file

@ -33,6 +33,7 @@
- (void)openFullPlaceDescriptionWithHtml:(NSString *_Nonnull)htmlString;
- (void)searchText:(NSString *_Nonnull)text;
- (void)openDrivingOptions;
- (void)showTrackRecordingPlacePage;
- (void)setPlacePageTopBound:(CGFloat)bound duration:(double)duration;

View file

@ -76,6 +76,7 @@ NSString *const kSettingsSegue = @"Map2Settings";
@property(nonatomic, readwrite) MWMMapViewControlsManager *controlsManager;
@property(nonatomic, readwrite) SearchOnMapManager *searchManager;
@property(nonatomic, readwrite) TrackRecordingManager *trackRecordingManager;
@property(nonatomic) BOOL disableStandbyOnLocationStateMode;
@ -119,9 +120,15 @@ NSString *const kSettingsSegue = @"Map2Settings";
#pragma mark - Map Navigation
- (void)showTrackRecordingPlacePage {
if ([self.trackRecordingManager contains:self]) {
[self dismissPlacePage];
return;
}
__block PlacePageData * placePageData = [[PlacePageData alloc] initWithTrackInfo:TrackRecordingManager.shared.trackRecordingInfo
elevationInfo:[MWMFrameworkHelper trackRecordingElevationInfo]];
[TrackRecordingManager.shared addObserver:self recordingIsActiveDidChangeHandler:^(TrackRecordingState state, TrackInfo * _Nonnull trackInfo) {
__weak __typeof(self) weakSelf = self;
[self.trackRecordingManager addObserver:self recordingIsActiveDidChangeHandler:^(TrackRecordingState state, TrackInfo * _Nonnull trackInfo) {
__strong __typeof(weakSelf) self = weakSelf;
switch (state) {
case TrackRecordingStateInactive:
[self stopObservingTrackRecordingUpdates];
@ -129,15 +136,19 @@ NSString *const kSettingsSegue = @"Map2Settings";
case TrackRecordingStateActive:
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
return;
[self.controlsManager.trackRecordingButton setHidden:YES];
[placePageData updateWithTrackInfo:trackInfo elevationInfo:[MWMFrameworkHelper trackRecordingElevationInfo]];
break;
}
}];
[self.controlsManager.trackRecordingButton setHidden:YES];
[self showOrUpdatePlacePage:placePageData];
}
- (void)stopObservingTrackRecordingUpdates {
[TrackRecordingManager.shared removeObserver:self];
[self.trackRecordingManager removeObserver:self];
if (self.trackRecordingManager.isActive)
[self.controlsManager.trackRecordingButton setHidden:NO];
}
- (void)showOrUpdatePlacePage:(PlacePageData *)data {
@ -146,9 +157,10 @@ NSString *const kSettingsSegue = @"Map2Settings";
self.controlsManager.trafficButtonHidden = YES;
if (self.placePageVC != nil) {
[PlacePageBuilder update:(PlacePageViewController *)self.placePageVC with:data];
[PlacePageBuilder update:self.placePageVC with:data];
return;
}
[self showPlacePageFor:data];
}
@ -754,6 +766,12 @@ NSString *const kSettingsSegue = @"Map2Settings";
return _searchManager;
}
- (TrackRecordingManager *)trackRecordingManager {
if (!_trackRecordingManager)
_trackRecordingManager = TrackRecordingManager.shared;
return _trackRecordingManager;
}
- (UIView * _Nullable)searchViewContainer {
return self.searchManager.viewController.view;
}

View file

@ -185,6 +185,7 @@ extension GlobalStyleSheet: IStyleSheet {
case .trackRecordingWidgetButton:
return .addFrom(Self.bottomTabBarButton) { s in
s.cornerRadius = 23
s.coloring = .red
}
case .blackOpaqueBackground:
return .add { s in

View file

@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "ic_track_save.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -524,6 +524,7 @@
ED914ABE2D351FF800973C45 /* UILabel+SetFontStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED914ABD2D351FF800973C45 /* UILabel+SetFontStyle.swift */; };
ED9857082C4ED02D00694F6C /* MailComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED9857072C4ED02D00694F6C /* MailComposer.swift */; };
ED9966802B94FBC20083CE55 /* ColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED99667D2B94FBC20083CE55 /* ColorPicker.swift */; };
ED9DDF882D6F151000645BC8 /* PlacePageTrackRecordingLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED9DDF872D6F151000645BC8 /* PlacePageTrackRecordingLayout.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 */; };
@ -1490,6 +1491,7 @@
ED914ABD2D351FF800973C45 /* UILabel+SetFontStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+SetFontStyle.swift"; sourceTree = "<group>"; };
ED9857072C4ED02D00694F6C /* MailComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposer.swift; sourceTree = "<group>"; };
ED99667D2B94FBC20083CE55 /* ColorPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPicker.swift; sourceTree = "<group>"; };
ED9DDF872D6F151000645BC8 /* PlacePageTrackRecordingLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacePageTrackRecordingLayout.swift; sourceTree = "<group>"; };
EDA1EAA32CC7ECAD00DBDCAA /* ElevationProfileFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElevationProfileFormatter.swift; sourceTree = "<group>"; };
EDBD68062B625724005DD151 /* LocationServicesDisabledAlert.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LocationServicesDisabledAlert.xib; sourceTree = "<group>"; };
EDBD680A2B62572E005DD151 /* LocationServicesDisabledAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationServicesDisabledAlert.swift; sourceTree = "<group>"; };
@ -3031,6 +3033,7 @@
99C6532123F2F506004322F3 /* IPlacePageLayout.swift */,
99F3EB0223F4178200C713F8 /* PlacePageCommonLayout.swift */,
993DF0B423F6B2EF00AC231A /* PlacePageTrackLayout.swift */,
ED9DDF872D6F151000645BC8 /* PlacePageTrackRecordingLayout.swift */,
);
path = Layouts;
sourceTree = "<group>";
@ -4630,6 +4633,7 @@
1DFA2F6A20D3B57400FB2C66 /* UIColor+PartnerColor.m in Sources */,
9989273B2449E60200260CE2 /* BottomMenuBuilder.swift in Sources */,
993DF10F23F6BDB100AC231A /* UIActivityIndicatorRenderer.swift in Sources */,
ED9DDF882D6F151000645BC8 /* PlacePageTrackRecordingLayout.swift in Sources */,
ED0B1FEF2CAA9A25006E31A4 /* UIView+Highlight.swift in Sources */,
99A614E423CDD1D900D8D8D0 /* UIButton+RuntimeAttributes.m in Sources */,
343E75981E5B1EE20041226A /* MWMCollectionViewController.m in Sources */,

View file

@ -79,8 +79,13 @@ extension BottomMenuInteractor: BottomMenuInteractorProtocol {
}
func toggleTrackRecording() {
trackRecorder.processAction(trackRecorder.recordingState == .active ? .stop : .start) { [weak self] in
self?.close()
switch trackRecorder.recordingState {
case .active:
break
case .inactive:
trackRecorder.processAction(.start)
}
close()
MapViewController.shared()?.showTrackRecordingPlacePage()
}
}

View file

@ -62,18 +62,26 @@ final class ActionBarViewController: UIViewController {
fatalError()
}
}
var buttons: [ActionBarButtonType] = []
if isRoutePlanning {
buttons.append(.routeFrom)
}
if placePageData.infoData?.phone != nil, AppInfo.shared().canMakeCalls {
buttons.append(.call)
}
if !isRoutePlanning {
buttons.append(.routeFrom)
switch placePageData.objectType {
case .POI, .bookmark, .track:
if isRoutePlanning {
buttons.append(.routeFrom)
}
if placePageData.infoData?.phone != nil, AppInfo.shared().canMakeCalls {
buttons.append(.call)
}
if !isRoutePlanning {
buttons.append(.routeFrom)
}
case .trackRecording:
break
@unknown default:
fatalError()
}
assert(buttons.count > 0)
guard !buttons.isEmpty else { return }
visibleButtons.append(buttons[0])
if buttons.count > 1 {
additionalButtons.append(contentsOf: buttons.suffix(from: 1))
@ -91,8 +99,7 @@ final class ActionBarViewController: UIViewController {
case .track:
buttons.append(.track)
case .trackRecording:
// TODO: implement for track recording
break
buttons.append(.saveTrackRecording)
@unknown default:
fatalError()
}
@ -104,7 +111,14 @@ final class ActionBarViewController: UIViewController {
}
private func configButton3() {
visibleButtons.append(.routeTo)
switch placePageData.objectType {
case .POI, .bookmark, .track:
visibleButtons.append(.routeTo)
case .trackRecording:
break
@unknown default:
fatalError()
}
}
private func configButton4() {

View file

@ -51,8 +51,6 @@ 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 = false
}
func onClosePress() {

View file

@ -2,7 +2,6 @@ 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?)
func showShareTrackMenu()
@ -78,15 +77,6 @@ extension PlacePageHeaderViewController: PlacePageHeaderViewProtocol {
}
}
var isShareButtonHidden: Bool {
get {
shareButton.isHidden
}
set {
shareButton.isHidden = newValue
}
}
func setTitle(_ title: String?, secondaryTitle: String?) {
titleText = title
secondaryText = secondaryTitle

View file

@ -15,8 +15,7 @@
case .track:
layout = PlacePageTrackLayout(interactor: interactor, storyboard: storyboard, data: data)
case .trackRecording:
// TODO: Implement PlacePageTrackRecordingLayout
fatalError("PlacePageTrackRecordingLayout is not implemented")
layout = PlacePageTrackRecordingLayout(interactor: interactor, storyboard: storyboard, data: data)
@unknown default:
fatalError()
}
@ -34,14 +33,14 @@
data: data,
mapViewController: MapViewController.shared()!)
let layout: IPlacePageLayout
let storyboard = viewController.storyboard!
switch data.objectType {
case .POI, .bookmark:
layout = PlacePageCommonLayout(interactor: interactor, storyboard: viewController.storyboard!, data: data)
layout = PlacePageCommonLayout(interactor: interactor, storyboard: storyboard, data: data)
case .track:
layout = PlacePageTrackLayout(interactor: interactor, storyboard: viewController.storyboard!, data: data)
layout = PlacePageTrackLayout(interactor: interactor, storyboard: storyboard, data: data)
case .trackRecording:
// TODO: Implement PlacePageTrackRecordingLayout
fatalError("PlacePageTrackRecordingLayout is not implemented")
layout = PlacePageTrackRecordingLayout(interactor: interactor, storyboard: storyboard, data: data)
@unknown default:
fatalError()
}

View file

@ -25,7 +25,7 @@ class PlacePageInteractor: NSObject {
private func updatePlacePageIfNeeded() {
let isBookmark = placePageData.bookmarkData != nil && bookmarksManager.hasBookmark(placePageData.bookmarkData!.bookmarkId)
let isTrack = placePageData.trackData != nil && bookmarksManager.hasTrack(placePageData.trackData!.trackId)
let isTrack = placePageData.trackData != nil/* && bookmarksManager.hasTrack(placePageData.trackData!.trackId)*/
guard isBookmark || isTrack else {
presenter?.closeAnimated()
return
@ -239,11 +239,11 @@ extension PlacePageInteractor: ActionBarViewControllerDelegate {
fatalError("More button should've been handled in ActionBarViewContoller")
case .track:
guard placePageData.trackData != nil else { return }
// TODO: This is temporary solution. Remove the dialog and use the MWMPlacePageManagerHelper.removeTrack
// TODO: (KK) This is temporary solution. Remove the dialog and use the MWMPlacePageManagerHelper.removeTrack
// directly here when the track recovery mechanism will be implemented.
showTrackDeletionConfirmationDialog()
case .saveTrackRecording:
// TODO: (KK) pass name
// TODO: (KK) pass name typed by user
TrackRecordingManager.shared.processAction(.stopAndSave(name: "")) { [weak self] result in
switch result {
case .success:
@ -287,8 +287,8 @@ extension PlacePageInteractor: ElevationProfileViewControllerDelegate {
}
func updateMapPoint(_ point: CLLocationCoordinate2D, distance: Double) {
guard let trackId = placePageData.trackData?.trackId else { return }
BookmarksManager.shared().setElevationActivePoint(point, distance: distance, trackId: trackId)
guard let trackData = placePageData.trackData, trackData.elevationProfileData?.isTrackRecording == false else { return }
BookmarksManager.shared().setElevationActivePoint(point, distance: distance, trackId: trackData.trackId)
}
}

View file

@ -3,6 +3,7 @@ typedef NS_ENUM(NSInteger, MWMActionBarButtonType) {
MWMActionBarButtonTypeBookingSearch,
MWMActionBarButtonTypeBookmark,
MWMActionBarButtonTypeTrack,
MWMActionBarButtonTypeSaveTrackRecording,
MWMActionBarButtonTypeCall,
MWMActionBarButtonTypeDownload,
MWMActionBarButtonTypeMore,

View file

@ -19,6 +19,8 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) {
case MWMActionBarButtonTypeBookmark:
case MWMActionBarButtonTypeTrack:
return L(isSelected ? @"delete" : @"save");
case MWMActionBarButtonTypeSaveTrackRecording:
return L(@"save");
case MWMActionBarButtonTypeRouteFrom:
return L(@"p2p_from_here");
case MWMActionBarButtonTypeRouteTo:
@ -55,7 +57,8 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) {
self.label.text = titleForButton(self.type, isSelected);
self.extraBackground.hidden = YES;
self.button.coloring = MWMButtonColoringBlack;
[self.button.imageView setContentMode:UIViewContentModeScaleAspectFit];
switch (self.type) {
case MWMActionBarButtonTypeDownload: {
if (self.mapDownloadProgress)
@ -108,6 +111,9 @@ NSString *titleForButton(MWMActionBarButtonType type, BOOL isSelected) {
[self.button setImage:[[UIImage imageNamed:@"ic_route_manager_trash"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
self.button.coloring = MWMButtonColoringRed;
break;
case MWMActionBarButtonTypeSaveTrackRecording:
[self.button setImage:[UIImage imageNamed:@"ic_placepage_save_track_recording"] forState:UIControlStateNormal];
break;
case MWMActionBarButtonTypeRouteFrom:
[self.button setImage:[UIImage imageNamed:@"ic_route_from"] forState:UIControlStateNormal];
break;

View file

@ -0,0 +1,92 @@
final class PlacePageTrackRecordingLayout: 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]
}()
lazy var headerViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
}()
lazy var editTrackViewController: PlacePageEditBookmarkOrTrackViewController = {
let vc = storyboard.instantiateViewController(ofType: PlacePageEditBookmarkOrTrackViewController.self)
vc.view.isHidden = true
vc.delegate = interactor
return vc
}()
lazy var elevationProfileViewController: 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]()
if let elevationProfileViewController {
viewControllers.append(elevationProfileViewController)
}
placePageData.onTrackRecordingProgressUpdate = { [weak self] in
self?.updateTrackRecordingRelatedSections()
}
return viewControllers
}
func calculateSteps(inScrollView scrollView: UIScrollView, compact: Bool) -> [PlacePageState] {
var steps: [PlacePageState] = []
let scrollHeight = scrollView.height
steps.append(.closed(-scrollHeight))
steps.append(.full(0))
return steps
}
}
private extension PlacePageTrackRecordingLayout {
func updateTrackRecordingRelatedSections() {
guard let elevationProfileViewController, let trackInfo = placePageData.trackData?.trackInfo else { return }
headerViewController.setTitle(placePageData.previewData.title, secondaryTitle: nil)
elevationProfileViewController.presenter?.update(trackInfo: trackInfo, profileData: placePageData.trackData?.elevationProfileData)
presenter?.layoutIfNeeded()
}
}