[ios] export single track from the place page as kml/gpx

Signed-off-by: Kiryl Kaveryn <kirylkaveryn@gmail.com>
This commit is contained in:
Kiryl Kaveryn 2025-02-19 19:51:32 +04:00 committed by Roman Tsisyk
parent 524f3fe358
commit 98ef2d61fb
11 changed files with 122 additions and 13 deletions

View file

@ -116,6 +116,14 @@ NS_SWIFT_NAME(BookmarksManager)
- urlToALocalFile: The local file URL containing the shared data. This parameter is guaranteed to be non-nil only if `status` is `MWMBookmarksShareStatusSuccess`. In other cases, it will be nil.
*/
- (void)shareAllCategoriesWithCompletion:(SharingResultCompletionHandler)completion;
/**
Shares a specific track with the given track ID.
@param trackId The identifier for the track to be shared.
@param fileType Text/Binary/GPX
*/
- (void)shareTrack:(MWMTrackID)trackId fileType:(MWMKmlFileType)fileType completion:(SharingResultCompletionHandler)completion;
- (void)finishShareCategory;
- (void)setNotificationsEnabled:(BOOL)enabled;

View file

@ -622,6 +622,12 @@ static KmlFileType convertFileTypeToCore(MWMKmlFileType fileType) {
});
}
- (void)shareTrack:(MWMTrackID)trackId fileType:(MWMKmlFileType)fileType completion:(SharingResultCompletionHandler)completion {
self.bm.PrepareTrackFileForSharing(trackId, [self, completion](auto sharingResult) {
[self handleSharingResult:sharingResult completion:completion];
}, convertFileTypeToCore(fileType));
}
- (void)handleSharingResult:(BookmarkManager::SharingResult)sharingResult completion:(SharingResultCompletionHandler)completion {
NSURL *urlToALocalFile = nil;
MWMBookmarksShareStatus status;

View file

@ -1,11 +1,12 @@
class PlacePageHeaderBuilder {
static func build(data: PlacePagePreviewData,
static func build(data: PlacePageData,
delegate: PlacePageHeaderViewControllerDelegate?,
headerType: PlacePageHeaderPresenter.HeaderType) -> PlacePageHeaderViewController {
let storyboard = UIStoryboard.instance(.placePage)
let viewController = storyboard.instantiateViewController(ofType: PlacePageHeaderViewController.self);
let presenter = PlacePageHeaderPresenter(view: viewController,
placePagePreviewData: data,
placePagePreviewData: data.previewData,
objectType: data.objectType,
delegate: delegate,
headerType: headerType)

View file

@ -1,14 +1,18 @@
protocol PlacePageHeaderPresenterProtocol: AnyObject {
var objectType: PlacePageObjectType { get }
func configure()
func onClosePress()
func onExpandPress()
func onShareButtonPress(from sourceView: UIView)
func onExportTrackButtonPress(_ type: KmlFileType, from sourceView: UIView)
}
protocol PlacePageHeaderViewControllerDelegate: AnyObject {
func previewDidPressClose()
func previewDidPressExpand()
func previewDidPressShare(from sourceView: UIView)
func previewDidPressExportTrack(_ type: KmlFileType, from sourceView: UIView)
}
class PlacePageHeaderPresenter {
@ -19,16 +23,19 @@ class PlacePageHeaderPresenter {
private weak var view: PlacePageHeaderViewProtocol?
private let placePagePreviewData: PlacePagePreviewData
let objectType: PlacePageObjectType
private weak var delegate: PlacePageHeaderViewControllerDelegate?
private let headerType: HeaderType
init(view: PlacePageHeaderViewProtocol,
placePagePreviewData: PlacePagePreviewData,
objectType: PlacePageObjectType,
delegate: PlacePageHeaderViewControllerDelegate?,
headerType: HeaderType) {
self.view = view
self.delegate = delegate
self.placePagePreviewData = placePagePreviewData
self.objectType = objectType
self.headerType = headerType
}
}
@ -45,7 +52,7 @@ extension PlacePageHeaderPresenter: PlacePageHeaderPresenterProtocol {
view?.isShadowViewHidden = false
}
// TODO: (KK) Enable share button for the tracks to share the whole track gpx/kml
view?.isShareButtonHidden = placePagePreviewData.coordinates == nil
view?.isShareButtonHidden = false
}
func onClosePress() {
@ -59,4 +66,8 @@ extension PlacePageHeaderPresenter: PlacePageHeaderPresenterProtocol {
func onShareButtonPress(from sourceView: UIView) {
delegate?.previewDidPressShare(from: sourceView)
}
func onExportTrackButtonPress(_ type: KmlFileType, from sourceView: UIView) {
delegate?.previewDidPressExportTrack(type, from: sourceView)
}
}

View file

@ -5,6 +5,7 @@ protocol PlacePageHeaderViewProtocol: AnyObject {
var isShareButtonHidden: Bool { get set }
func setTitle(_ title: String?, secondaryTitle: String?)
func showShareTrackMenu()
}
class PlacePageHeaderViewController: UIViewController {
@ -33,6 +34,10 @@ class PlacePageHeaderViewController: UIViewController {
}
closeButton.setImage(UIImage(named: "ic_close")!)
shareButton.setImage(UIImage(named: "ic_share")!)
if presenter?.objectType == .track {
configureTrackSharingMenu()
}
}
@objc func onExpandPressed(sender: UITapGestureRecognizer) {
@ -114,4 +119,40 @@ extension PlacePageHeaderViewController: PlacePageHeaderViewProtocol {
attributedText.append(NSAttributedString(string: "\n" + unwrappedSecondaryTitle, attributes: secondaryTitleAttributes))
titleLabel?.attributedText = attributedText
}
func showShareTrackMenu() {
if #available(iOS 14.0, *) {
// The menu will be shown by the shareButton itself
} else {
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let kmlAction = UIAlertAction(title: L("export_file"), style: .default) { [weak self] _ in
guard let self else { return }
self.presenter?.onExportTrackButtonPress(.text, from: self.shareButton)
}
let gpxAction = UIAlertAction(title: L("export_file_gpx"), style: .default) { [weak self] _ in
guard let self else { return }
self.presenter?.onExportTrackButtonPress(.gpx, from: self.shareButton)
}
alert.addAction(kmlAction)
alert.addAction(gpxAction)
present(alert, animated: true, completion: nil)
}
}
private func configureTrackSharingMenu() {
if #available(iOS 14.0, *) {
let menu = UIMenu(title: "", image: nil, children: [
UIAction(title: L("export_file"), image: nil, handler: { [weak self] _ in
guard let self else { return }
self.presenter?.onExportTrackButtonPress(.text, from: self.shareButton)
}),
UIAction(title: L("export_file_gpx"), image: nil, handler: { [weak self] _ in
guard let self else { return }
self.presenter?.onExportTrackButtonPress(.gpx, from: self.shareButton)
}),
])
shareButton.menu = menu
shareButton.showsMenuAsPrimaryAction = true
}
}
}

View file

@ -20,7 +20,7 @@
@unknown default:
fatalError()
}
let presenter = PlacePagePresenter(view: viewController)
let presenter = PlacePagePresenter(view: viewController, headerView: layout.headerViewController)
viewController.setLayout(layout)
viewController.interactor = interactor
interactor.presenter = presenter
@ -45,7 +45,7 @@
@unknown default:
fatalError()
}
let presenter = PlacePagePresenter(view: viewController)
let presenter = PlacePagePresenter(view: viewController, headerView: layout.headerViewController)
viewController.interactor = interactor
interactor.presenter = presenter
layout.presenter = presenter

View file

@ -295,8 +295,42 @@ extension PlacePageInteractor: PlacePageHeaderViewControllerDelegate {
func previewDidPressShare(from sourceView: UIView) {
guard let mapViewController else { return }
let shareViewController = ActivityViewController.share(forPlacePage: placePageData)
shareViewController.present(inParentViewController: mapViewController, anchorView: sourceView)
switch placePageData.objectType {
case .POI, .bookmark:
let shareViewController = ActivityViewController.share(forPlacePage: placePageData)
shareViewController.present(inParentViewController: mapViewController, anchorView: sourceView)
case .track:
presenter?.showShareTrackMenu()
default:
fatalError()
}
}
func previewDidPressExportTrack(_ type: KmlFileType, from sourceView: UIView) {
guard let trackId = placePageData.trackData?.trackId else {
fatalError("Track data should not be nil during the track export")
}
bookmarksManager.shareTrack(trackId, fileType: type) { [weak self] status, url in
guard let self, let mapViewController else { return }
switch status {
case .success:
guard let url else { fatalError("Invalid sharing url") }
let shareViewController = ActivityViewController.share(for: url, message: self.placePageData.previewData.title!) { _,_,_,_ in
self.bookmarksManager.finishShareCategory()
}
shareViewController.present(inParentViewController: mapViewController, anchorView: sourceView)
case .emptyCategory:
self.showAlert(withTitle: L("bookmarks_error_title_share_empty"),
message: L("bookmarks_error_message_share_empty"))
case .archiveError, .fileError:
self.showAlert(withTitle: L("dialog_routing_system_error"),
message: L("bookmarks_error_message_share_general"))
}
}
}
private func showAlert(withTitle title: String, message: String) {
MWMAlertViewController.activeAlert().presentInfoAlert(title, text: message)
}
}

View file

@ -24,6 +24,7 @@ enum PlacePageState {
protocol IPlacePageLayout: AnyObject {
var presenter: PlacePagePresenterProtocol? { get set }
var headerViewControllers: [UIViewController] { get }
var headerViewController: PlacePageHeaderViewController { get }
var bodyViewControllers: [UIViewController] { get }
var actionBar: ActionBarViewController? { get }
var navigationBar: UIViewController? { get }

View file

@ -27,7 +27,7 @@ class PlacePageCommonLayout: NSObject, IPlacePageLayout {
}
lazy var headerViewController: PlacePageHeaderViewController = {
PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .flexible)
PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}()
lazy var previewViewController: PlacePagePreviewViewController = {
@ -81,7 +81,7 @@ class PlacePageCommonLayout: NSObject, IPlacePageLayout {
} ()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .fixed)
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
} ()
init(interactor: PlacePageInteractor, storyboard: UIStoryboard, data: PlacePageData) {

View file

@ -22,7 +22,7 @@ class PlacePageTrackLayout: IPlacePageLayout {
}()
lazy var headerViewController: PlacePageHeaderViewController = {
PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .flexible)
PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .flexible)
}()
lazy var previewViewController: PlacePagePreviewViewController = {
@ -32,7 +32,7 @@ class PlacePageTrackLayout: IPlacePageLayout {
}()
lazy var placePageNavigationViewController: PlacePageHeaderViewController = {
return PlacePageHeaderBuilder.build(data: placePageData.previewData, delegate: interactor, headerType: .fixed)
return PlacePageHeaderBuilder.build(data: placePageData, delegate: interactor, headerType: .fixed)
}()
lazy var editTrackViewController: PlacePageEditBookmarkOrTrackViewController = {

View file

@ -4,13 +4,16 @@ protocol PlacePagePresenterProtocol: AnyObject {
func showNextStop()
func closeAnimated()
func showAlert(_ alert: UIAlertController)
func showShareTrackMenu()
}
class PlacePagePresenter: NSObject {
final class PlacePagePresenter: NSObject {
private weak var view: PlacePageViewProtocol!
private weak var headerView: PlacePageHeaderViewProtocol!
init(view: PlacePageViewProtocol) {
init(view: PlacePageViewProtocol, headerView: PlacePageHeaderViewProtocol) {
self.view = view
self.headerView = headerView
}
}
@ -36,4 +39,8 @@ extension PlacePagePresenter: PlacePagePresenterProtocol {
func showAlert(_ alert: UIAlertController) {
view.showAlert(alert)
}
func showShareTrackMenu() {
headerView.showShareTrackMenu()
}
}