diff --git a/iphone/Maps/Classes/CarPlay/Template Builders/SettingsTemplateBuilder.swift b/iphone/Maps/Classes/CarPlay/Template Builders/SettingsTemplateBuilder.swift index 8638544d6..6b6f73589 100644 --- a/iphone/Maps/Classes/CarPlay/Template Builders/SettingsTemplateBuilder.swift +++ b/iphone/Maps/Classes/CarPlay/Template Builders/SettingsTemplateBuilder.swift @@ -15,6 +15,7 @@ final class SettingsTemplateBuilder { return [createUnpavedButton(options: options), createTollButton(options: options), createFerryButton(options: options), + createStepsButton(options: options), createSpeedcamButton()] } @@ -72,6 +73,24 @@ final class SettingsTemplateBuilder { } return ferryButton } + + private class func createStepsButton(options: RoutingOptions) -> CPGridButton { + var stepsIconName = "options.steps" + if options.avoidSteps { stepsIconName += ".slash" } + let configuration = UIImage.SymbolConfiguration(textStyle: .title1) + var image = UIImage(named: stepsIconName, in: nil, with: configuration)! + if #unavailable(iOS 26) { + image = image.withTintColor(.white, renderingMode: .alwaysTemplate) + image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate) + } + let stepsButton = CPGridButton(titleVariants: [L("avoid_steps")], image: image) { _ in + options.avoidSteps = !options.avoidSteps + options.save() + CarPlayService.shared.updateRouteAfterChangingSettings() + CarPlayService.shared.popTemplate(animated: true) + } + return stepsButton + } private class func createSpeedcamButton() -> CPGridButton { var speedcamIconName = "options.speedcamera" diff --git a/iphone/Maps/Core/Routing/MWMRouter.h b/iphone/Maps/Core/Routing/MWMRouter.h index c7a9f0c2c..86d8f5798 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.h +++ b/iphone/Maps/Core/Routing/MWMRouter.h @@ -5,7 +5,8 @@ typedef NS_ENUM(NSInteger, MWMRoadType) { MWMRoadTypeToll, MWMRoadTypeDirty, MWMRoadTypeFerry, - MWMRoadTypeMotorway + MWMRoadTypeMotorway, + MWMRoadTypeSteps }; typedef void (^MWMImageHeightBlock)(UIImage *, NSString *, NSString *); diff --git a/iphone/Maps/Core/Routing/MWMRouter.mm b/iphone/Maps/Core/Routing/MWMRouter.mm index e1acb63ef..9d2bdaceb 100644 --- a/iphone/Maps/Core/Routing/MWMRouter.mm +++ b/iphone/Maps/Core/Routing/MWMRouter.mm @@ -598,6 +598,9 @@ char const *kRenderAltitudeImagesQueueLabel = "mapsme.mwmrouter.renderAltitudeIm case MWMRoadTypeMotorway: options.avoidMotorway = YES; break; + case MWMRoadTypeSteps: + options.avoidSteps = YES; + break; } [options save]; [self rebuildWithBestRouter:YES]; diff --git a/iphone/Maps/Core/Settings/MWMRoutingOptions.h b/iphone/Maps/Core/Settings/MWMRoutingOptions.h index d1251fa38..b45daf049 100644 --- a/iphone/Maps/Core/Settings/MWMRoutingOptions.h +++ b/iphone/Maps/Core/Settings/MWMRoutingOptions.h @@ -9,6 +9,7 @@ NS_SWIFT_NAME(RoutingOptions) @property(nonatomic) BOOL avoidDirty; @property(nonatomic) BOOL avoidFerry; @property(nonatomic) BOOL avoidMotorway; +@property(nonatomic) BOOL avoidSteps; @property(nonatomic, readonly) BOOL hasOptions; - (void)save; diff --git a/iphone/Maps/Core/Settings/MWMRoutingOptions.mm b/iphone/Maps/Core/Settings/MWMRoutingOptions.mm index 2906b6cb0..c05892a7f 100644 --- a/iphone/Maps/Core/Settings/MWMRoutingOptions.mm +++ b/iphone/Maps/Core/Settings/MWMRoutingOptions.mm @@ -51,8 +51,16 @@ [self setOption:(routing::RoutingOptions::Road::Motorway) enabled:avoid]; } +- (BOOL)avoidSteps { + return _options.Has(routing::RoutingOptions::Road::Steps); +} + +- (void)setAvoidSteps:(BOOL)avoid { + [self setOption:(routing::RoutingOptions::Road::Steps) enabled:avoid]; +} + - (BOOL)hasOptions { - return self.avoidToll || self.avoidDirty || self.avoidFerry || self.avoidMotorway; + return self.avoidToll || self.avoidDirty || self.avoidFerry || self.avoidMotorway || self.avoidSteps; } - (void)save { @@ -73,7 +81,7 @@ } MWMRoutingOptions *another = (MWMRoutingOptions *)object; return another.avoidToll == self.avoidToll && another.avoidDirty == self.avoidDirty && - another.avoidFerry == self.avoidFerry && another.avoidMotorway == self.avoidMotorway; + another.avoidFerry == self.avoidFerry && another.avoidMotorway == self.avoidMotorway && another.avoidSteps == self.avoidSteps; } @end diff --git a/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/Contents.json b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/Contents.json new file mode 100644 index 000000000..9053da09a --- /dev/null +++ b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "symbols" : [ + { + "filename" : "options.steps.slash.svg", + "idiom" : "universal" + } + ] +} diff --git a/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/options.steps.slash.svg b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/options.steps.slash.svg new file mode 100644 index 000000000..bfebf73e2 --- /dev/null +++ b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.slash.symbolset/options.steps.slash.svg @@ -0,0 +1,121 @@ + + + + + + + + + + Weight/Scale Variations + Ultralight + Thin + Light + Regular + Medium + Semibold + Bold + Heavy + Black + + + + + + + + + + + Design Variations + Symbols are supported in up to nine weights and three scales. + For optimal layout with text and other symbols, vertically align + symbols with the adjacent text. + + + + + + Margins + Leading and trailing margins on the left and right side of each symbol + can be adjusted by modifying the x-location of the margin guidelines. + Modifications are automatically applied proportionally to all + scales and weights. + + + + Exporting + Symbols should be outlined when exporting to ensure the + design is preserved when submitting to Xcode. + Template v.7.0 + Requires Xcode 17 or greater + Generated from + Typeset at 100.0 points + Small + Medium + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/Contents.json b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/Contents.json new file mode 100644 index 000000000..50bd67954 --- /dev/null +++ b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "symbols" : [ + { + "filename" : "options.steps.svg", + "idiom" : "universal" + } + ] +} diff --git a/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/options.steps.svg b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/options.steps.svg new file mode 100644 index 000000000..23f474dcd --- /dev/null +++ b/iphone/Maps/Images.xcassets/Interface/Symbols/options.steps.symbolset/options.steps.svg @@ -0,0 +1,109 @@ + + + + + + + + + + Weight/Scale Variations + Ultralight + Thin + Light + Regular + Medium + Semibold + Bold + Heavy + Black + + + + + + + + + + + Design Variations + Symbols are supported in up to nine weights and three scales. + For optimal layout with text and other symbols, vertically align + symbols with the adjacent text. + + + + + + Margins + Leading and trailing margins on the left and right side of each symbol + can be adjusted by modifying the x-location of the margin guidelines. + Modifications are automatically applied proportionally to all + scales and weights. + + + + Exporting + Symbols should be outlined when exporting to ensure the + design is preserved when submitting to Xcode. + Template v.7.0 + Requires Xcode 17 or greater + Generated from options.steps + Typeset at 100.0 points + Small + Medium + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iphone/Maps/LocalizedStrings/de.lproj/Localizable.strings b/iphone/Maps/LocalizedStrings/de.lproj/Localizable.strings index 12ab8b98c..436a20f3a 100644 --- a/iphone/Maps/LocalizedStrings/de.lproj/Localizable.strings +++ b/iphone/Maps/LocalizedStrings/de.lproj/Localizable.strings @@ -825,6 +825,7 @@ "avoid_unpaved" = "Unbefest. Straßen vermeiden"; /* Recommended length for CarPlay and Android Auto is around 25-27 characters */ +"avoid_steps" = "Stufen vermeiden"; "avoid_ferry" = "Fähren vermeiden"; "avoid_motorways" = "Autobahnen vermeiden"; "unable_to_calc_alert_title" = "Route kann nicht berechnet werden"; diff --git a/iphone/Maps/LocalizedStrings/en-GB.lproj/Localizable.strings b/iphone/Maps/LocalizedStrings/en-GB.lproj/Localizable.strings index 32ad21682..2c2c368b7 100644 --- a/iphone/Maps/LocalizedStrings/en-GB.lproj/Localizable.strings +++ b/iphone/Maps/LocalizedStrings/en-GB.lproj/Localizable.strings @@ -846,6 +846,7 @@ "avoid_unpaved" = "Avoid unpaved roads"; /* Recommended length for CarPlay and Android Auto is around 25-27 characters */ +"avoid_steps" = "Avoid steps"; "avoid_ferry" = "Avoid ferries"; "avoid_motorways" = "Avoid motorways"; "unable_to_calc_alert_title" = "Unable to calculate route"; diff --git a/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings b/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings index c0b3bc0ad..5a0f46da4 100644 --- a/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings +++ b/iphone/Maps/LocalizedStrings/en.lproj/Localizable.strings @@ -868,6 +868,7 @@ "avoid_unpaved" = "Avoid unpaved roads"; /* Recommended length for CarPlay and Android Auto is around 25-27 characters */ +"avoid_steps" = "Avoid steps"; "avoid_ferry" = "Avoid ferries"; "avoid_motorways" = "Avoid freeways"; "unable_to_calc_alert_title" = "Unable to calculate route"; diff --git a/iphone/Maps/Model/Settings.swift b/iphone/Maps/Model/Settings.swift index ba008c58e..38bf484f8 100644 --- a/iphone/Maps/Model/Settings.swift +++ b/iphone/Maps/Model/Settings.swift @@ -407,6 +407,21 @@ import Combine } + /// If steps should be avoided during routing + @objc static var shouldAvoidStepsWhileRouting: Bool { + get { + return RoutingOptions().avoidSteps + } + set { + let routingOptions = RoutingOptions() + routingOptions.avoidSteps = newValue + routingOptions.save() + + NotificationCenter.default.post(name: routingOptionsChangedNotificationName, object: nil) + } + } + + // MARK: Methods diff --git a/iphone/Maps/UI/Routing/RoutingOptionsView.swift b/iphone/Maps/UI/Routing/RoutingOptionsView.swift index 9941d275d..8559e8010 100644 --- a/iphone/Maps/UI/Routing/RoutingOptionsView.swift +++ b/iphone/Maps/UI/Routing/RoutingOptionsView.swift @@ -24,6 +24,10 @@ struct RoutingOptionsView: View { @State var shouldAvoidMotorwaysWhileRouting: Bool = false + /// If steps should be avoided during routing + @State var shouldAvoidStepsWhileRouting: Bool = false + + /// The actual view var body: some View { NavigationView { @@ -40,6 +44,9 @@ struct RoutingOptionsView: View { Toggle("avoid_motorways", isOn: $shouldAvoidMotorwaysWhileRouting) .tint(.accent) + + Toggle("avoid_steps", isOn: $shouldAvoidStepsWhileRouting) + .tint(.accent) } } .navigationTitle(String(localized: "driving_options_title")) @@ -60,6 +67,7 @@ struct RoutingOptionsView: View { shouldAvoidUnpavedRoadsWhileRouting = Settings.shouldAvoidUnpavedRoadsWhileRouting shouldAvoidFerriesWhileRouting = Settings.shouldAvoidFerriesWhileRouting shouldAvoidMotorwaysWhileRouting = Settings.shouldAvoidMotorwaysWhileRouting + shouldAvoidStepsWhileRouting = Settings.shouldAvoidStepsWhileRouting } .onChange(of: shouldAvoidTollRoadsWhileRouting) { changedShouldAvoidTollRoadsWhileRouting in Settings.shouldAvoidTollRoadsWhileRouting = changedShouldAvoidTollRoadsWhileRouting @@ -76,6 +84,9 @@ struct RoutingOptionsView: View { .onChange(of: shouldAvoidMotorwaysWhileRouting) { changedShouldAvoidMotorwaysWhileRouting in Settings.shouldAvoidMotorwaysWhileRouting = changedShouldAvoidMotorwaysWhileRouting } + .onChange(of: shouldAvoidStepsWhileRouting) { changedShouldAvoidStepsWhileRouting in + Settings.shouldAvoidStepsWhileRouting = changedShouldAvoidStepsWhileRouting + } .accentColor(.toolbarAccent) } } diff --git a/iphone/Maps/UI/Settings/SettingsNavigationView.swift b/iphone/Maps/UI/Settings/SettingsNavigationView.swift index 01096b02c..b1c420301 100644 --- a/iphone/Maps/UI/Settings/SettingsNavigationView.swift +++ b/iphone/Maps/UI/Settings/SettingsNavigationView.swift @@ -44,6 +44,10 @@ struct SettingsNavigationView: View { @State var shouldAvoidMotorwaysWhileRouting: Bool = false + /// If steps should be avoided during routing + @State var shouldAvoidStepsWhileRouting: Bool = false + + /// The actual view var body: some View { List { @@ -120,6 +124,9 @@ struct SettingsNavigationView: View { Toggle("avoid_motorways", isOn: $shouldAvoidMotorwaysWhileRouting) .tint(.accent) + + Toggle("avoid_steps", isOn: $shouldAvoidStepsWhileRouting) + .tint(.accent) } header: { Text("driving_options_title") } @@ -138,6 +145,7 @@ struct SettingsNavigationView: View { shouldAvoidUnpavedRoadsWhileRouting = Settings.shouldAvoidUnpavedRoadsWhileRouting shouldAvoidFerriesWhileRouting = Settings.shouldAvoidFerriesWhileRouting shouldAvoidMotorwaysWhileRouting = Settings.shouldAvoidMotorwaysWhileRouting + shouldAvoidStepsWhileRouting = Settings.shouldAvoidStepsWhileRouting } .onChange(of: hasPerspectiveViewWhileRouting) { changedHasPerspectiveViewWhileRouting in Settings.hasPerspectiveViewWhileRouting = changedHasPerspectiveViewWhileRouting @@ -174,5 +182,8 @@ struct SettingsNavigationView: View { .onChange(of: shouldAvoidMotorwaysWhileRouting) { changedShouldAvoidMotorwaysWhileRouting in Settings.shouldAvoidMotorwaysWhileRouting = changedShouldAvoidMotorwaysWhileRouting } + .onChange(of: shouldAvoidStepsWhileRouting) { changedShouldAvoidStepsWhileRouting in + Settings.shouldAvoidStepsWhileRouting = changedShouldAvoidStepsWhileRouting + } } }