Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
|
|
@ -0,0 +1,129 @@
|
|||
import CarPlay
|
||||
|
||||
final class ListTemplateBuilder {
|
||||
enum ListTemplateType {
|
||||
case history
|
||||
case bookmarkLists
|
||||
case bookmarks(category: BookmarkGroup)
|
||||
case searchResults(results: [MWMCarPlaySearchResultObject])
|
||||
}
|
||||
|
||||
enum BarButtonType {
|
||||
case bookmarks
|
||||
case search
|
||||
}
|
||||
|
||||
// MARK: - CPListTemplate builder
|
||||
class func buildListTemplate(for type: ListTemplateType) -> CPListTemplate {
|
||||
var title = ""
|
||||
var trailingNavigationBarButtons = [CPBarButton]()
|
||||
switch type {
|
||||
case .history:
|
||||
title = L("pick_destination")
|
||||
let bookmarksButton = buildBarButton(type: .bookmarks) { _ in
|
||||
let listTemplate = ListTemplateBuilder.buildListTemplate(for: .bookmarkLists)
|
||||
CarPlayService.shared.pushTemplate(listTemplate, animated: true)
|
||||
}
|
||||
let searchButton = buildBarButton(type: .search) { _ in
|
||||
if CarPlayService.shared.isKeyboardLimited {
|
||||
CarPlayService.shared.showKeyboardAlert()
|
||||
} else {
|
||||
let searchTemplate = SearchTemplateBuilder.buildSearchTemplate()
|
||||
CarPlayService.shared.pushTemplate(searchTemplate, animated: true)
|
||||
}
|
||||
}
|
||||
trailingNavigationBarButtons = [searchButton, bookmarksButton]
|
||||
case .bookmarkLists:
|
||||
title = L("bookmarks")
|
||||
case .searchResults:
|
||||
title = L("search_results")
|
||||
case .bookmarks(let category):
|
||||
title = category.title
|
||||
}
|
||||
|
||||
let sections = buildSectionsForType(type)
|
||||
let template = CPListTemplate(title: title, sections: sections)
|
||||
template.trailingNavigationBarButtons = trailingNavigationBarButtons
|
||||
return template
|
||||
}
|
||||
|
||||
private class func buildSectionsForType(_ type: ListTemplateType) -> [CPListSection] {
|
||||
switch type {
|
||||
case .history:
|
||||
return buildHistorySections()
|
||||
case .bookmarks(let category):
|
||||
return buildBookmarksSections(categoryId: category.categoryId)
|
||||
case .bookmarkLists:
|
||||
return buildBookmarkListsSections()
|
||||
case .searchResults(let results):
|
||||
return buildSearchResultsSections(results)
|
||||
}
|
||||
}
|
||||
|
||||
private class func buildHistorySections() -> [CPListSection] {
|
||||
let searchQueries = FrameworkHelper.obtainLastSearchQueries()
|
||||
let items = searchQueries.map({ (text) -> CPListItem in
|
||||
let item = CPListItem(text: text, detailText: nil, image: UIImage(named: "recent"))
|
||||
item.userInfo = ListItemInfo(type: CPConstants.ListItemType.history,
|
||||
metadata: nil)
|
||||
return item
|
||||
})
|
||||
return [CPListSection(items: items)]
|
||||
}
|
||||
|
||||
private class func buildBookmarkListsSections() -> [CPListSection] {
|
||||
let bookmarkManager = BookmarksManager.shared()
|
||||
let categories = bookmarkManager.sortedUserCategories()
|
||||
let items: [CPListItem] = categories.compactMap({ category in
|
||||
if category.bookmarksCount == 0 { return nil }
|
||||
let placesString = category.placesCountTitle()
|
||||
let item = CPListItem(text: category.title, detailText: placesString)
|
||||
item.userInfo = ListItemInfo(type: CPConstants.ListItemType.bookmarkLists,
|
||||
metadata: CategoryInfo(category: category))
|
||||
return item
|
||||
})
|
||||
return [CPListSection(items: items)]
|
||||
}
|
||||
|
||||
private class func buildBookmarksSections(categoryId: MWMMarkGroupID) -> [CPListSection] {
|
||||
let bookmarkManager = BookmarksManager.shared()
|
||||
let bookmarks = bookmarkManager.bookmarks(forCategory: categoryId)
|
||||
var items = bookmarks.map({ (bookmark) -> CPListItem in
|
||||
let item = CPListItem(text: bookmark.prefferedName, detailText: bookmark.address)
|
||||
item.userInfo = ListItemInfo(type: CPConstants.ListItemType.bookmarks,
|
||||
metadata: BookmarkInfo(categoryId: categoryId,
|
||||
bookmarkId: bookmark.bookmarkId))
|
||||
return item
|
||||
})
|
||||
let maxItemCount = CPListTemplate.maximumItemCount - 1
|
||||
if items.count >= maxItemCount {
|
||||
items = Array(items.prefix(maxItemCount))
|
||||
let cropWarning = CPListItem(text: L("not_all_shown_bookmarks_carplay"), detailText: L("switch_to_phone_bookmarks_carplay"))
|
||||
cropWarning.isEnabled = false
|
||||
items.append(cropWarning)
|
||||
}
|
||||
return [CPListSection(items: items)]
|
||||
}
|
||||
|
||||
private class func buildSearchResultsSections(_ results: [MWMCarPlaySearchResultObject]) -> [CPListSection] {
|
||||
var items = [CPListItem]()
|
||||
for object in results {
|
||||
let item = CPListItem(text: object.title, detailText: object.address)
|
||||
item.userInfo = ListItemInfo(type: CPConstants.ListItemType.searchResults,
|
||||
metadata: SearchResultInfo(originalRow: object.originalRow))
|
||||
items.append(item)
|
||||
}
|
||||
return [CPListSection(items: items)]
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CPBarButton builder
|
||||
private class func buildBarButton(type: BarButtonType, action: ((CPBarButton) -> Void)?) -> CPBarButton {
|
||||
switch type {
|
||||
case .bookmarks:
|
||||
return CPBarButton(image: UIImage(systemName: "list.star")!, handler: action)
|
||||
case .search:
|
||||
return CPBarButton(image: UIImage(systemName: "keyboard.fill")!, handler: action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
import CarPlay
|
||||
|
||||
final class MapTemplateBuilder {
|
||||
enum MapButtonType {
|
||||
case startPanning
|
||||
case zoomIn
|
||||
case zoomOut
|
||||
}
|
||||
enum BarButtonType {
|
||||
case dismissPaning
|
||||
case destination
|
||||
case recenter
|
||||
case settings
|
||||
case mute
|
||||
case unmute
|
||||
case redirectRoute
|
||||
case endRoute
|
||||
}
|
||||
|
||||
private enum Constants {
|
||||
static let carPlayGuidanceBackgroundColor = UIColor(46, 100, 51, 1.0)
|
||||
}
|
||||
|
||||
// MARK: - CPMapTemplate builders
|
||||
class func buildBaseTemplate(positionMode: MWMMyPositionMode) -> CPMapTemplate {
|
||||
let mapTemplate = CPMapTemplate()
|
||||
mapTemplate.hidesButtonsWithNavigationBar = false
|
||||
configureBaseUI(mapTemplate: mapTemplate)
|
||||
if positionMode == .pendingPosition {
|
||||
mapTemplate.leadingNavigationBarButtons = []
|
||||
} else if positionMode == .follow || positionMode == .followAndRotate {
|
||||
setupDestinationButton(mapTemplate: mapTemplate)
|
||||
} else {
|
||||
setupRecenterButton(mapTemplate: mapTemplate)
|
||||
}
|
||||
return mapTemplate
|
||||
}
|
||||
|
||||
class func buildNavigationTemplate() -> CPMapTemplate {
|
||||
let mapTemplate = CPMapTemplate()
|
||||
mapTemplate.hidesButtonsWithNavigationBar = false
|
||||
configureNavigationUI(mapTemplate: mapTemplate)
|
||||
return mapTemplate
|
||||
}
|
||||
|
||||
class func buildTripPreviewTemplate(forTrips trips: [CPTrip]) -> CPMapTemplate {
|
||||
let mapTemplate = CPMapTemplate()
|
||||
mapTemplate.userInfo = MapInfo(type: CPConstants.TemplateType.preview, trips: trips)
|
||||
mapTemplate.mapButtons = []
|
||||
mapTemplate.leadingNavigationBarButtons = []
|
||||
let settingsButton = buildBarButton(type: .settings) { _ in
|
||||
mapTemplate.userInfo = MapInfo(type: CPConstants.TemplateType.previewSettings)
|
||||
let gridTemplate = SettingsTemplateBuilder.buildGridTemplate()
|
||||
CarPlayService.shared.pushTemplate(gridTemplate, animated: true)
|
||||
}
|
||||
mapTemplate.trailingNavigationBarButtons = [settingsButton]
|
||||
return mapTemplate
|
||||
}
|
||||
|
||||
// MARK: - MapTemplate UI configs
|
||||
class func configureBaseUI(mapTemplate: CPMapTemplate) {
|
||||
mapTemplate.userInfo = MapInfo(type: CPConstants.TemplateType.main)
|
||||
let panningButton = buildMapButton(type: .startPanning) { _ in
|
||||
mapTemplate.showPanningInterface(animated: true)
|
||||
}
|
||||
let zoomInButton = buildMapButton(type: .zoomIn) { _ in
|
||||
FrameworkHelper.zoomMap(.in)
|
||||
}
|
||||
let zoomOutButton = buildMapButton(type: .zoomOut) { _ in
|
||||
FrameworkHelper.zoomMap(.out)
|
||||
}
|
||||
mapTemplate.mapButtons = [panningButton, zoomInButton, zoomOutButton]
|
||||
|
||||
let settingsButton = buildBarButton(type: .settings) { _ in
|
||||
let gridTemplate = SettingsTemplateBuilder.buildGridTemplate()
|
||||
CarPlayService.shared.pushTemplate(gridTemplate, animated: true)
|
||||
}
|
||||
mapTemplate.trailingNavigationBarButtons = [settingsButton]
|
||||
}
|
||||
|
||||
class func configurePanUI(mapTemplate: CPMapTemplate) {
|
||||
let zoomInButton = buildMapButton(type: .zoomIn) { _ in
|
||||
FrameworkHelper.zoomMap(.in)
|
||||
}
|
||||
let zoomOutButton = buildMapButton(type: .zoomOut) { _ in
|
||||
FrameworkHelper.zoomMap(.out)
|
||||
}
|
||||
mapTemplate.mapButtons = [zoomInButton, zoomOutButton]
|
||||
|
||||
let doneButton = buildBarButton(type: .dismissPaning) { _ in
|
||||
mapTemplate.dismissPanningInterface(animated: true)
|
||||
}
|
||||
mapTemplate.leadingNavigationBarButtons = []
|
||||
mapTemplate.trailingNavigationBarButtons = [doneButton]
|
||||
}
|
||||
|
||||
class func configureNavigationUI(mapTemplate: CPMapTemplate) {
|
||||
mapTemplate.userInfo = MapInfo(type: CPConstants.TemplateType.navigation)
|
||||
let panningButton = buildMapButton(type: .startPanning) { _ in
|
||||
mapTemplate.showPanningInterface(animated: true)
|
||||
}
|
||||
mapTemplate.mapButtons = [panningButton]
|
||||
setupMuteAndRedirectButtons(template: mapTemplate)
|
||||
let endButton = buildBarButton(type: .endRoute) { _ in
|
||||
CarPlayService.shared.cancelCurrentTrip()
|
||||
}
|
||||
mapTemplate.trailingNavigationBarButtons = [endButton]
|
||||
mapTemplate.guidanceBackgroundColor = Constants.carPlayGuidanceBackgroundColor
|
||||
}
|
||||
|
||||
// MARK: - Conditional navigation buttons
|
||||
class func setupDestinationButton(mapTemplate: CPMapTemplate) {
|
||||
let destinationButton = buildBarButton(type: .destination) { _ in
|
||||
let listTemplate = ListTemplateBuilder.buildListTemplate(for: .history)
|
||||
CarPlayService.shared.pushTemplate(listTemplate, animated: true)
|
||||
}
|
||||
mapTemplate.leadingNavigationBarButtons = [destinationButton]
|
||||
}
|
||||
|
||||
class func setupRecenterButton(mapTemplate: CPMapTemplate) {
|
||||
let recenterButton = buildBarButton(type: .recenter) { _ in
|
||||
FrameworkHelper.switchMyPositionMode()
|
||||
}
|
||||
mapTemplate.leadingNavigationBarButtons = [recenterButton]
|
||||
}
|
||||
|
||||
private class func setupMuteAndRedirectButtons(template: CPMapTemplate) {
|
||||
let redirectButton = buildBarButton(type: .redirectRoute) { _ in
|
||||
let listTemplate = ListTemplateBuilder.buildListTemplate(for: .history)
|
||||
CarPlayService.shared.pushTemplate(listTemplate, animated: true)
|
||||
}
|
||||
if MWMTextToSpeech.isTTSEnabled() {
|
||||
let muteButton = buildBarButton(type: .mute) { _ in
|
||||
MWMTextToSpeech.tts().active = false
|
||||
setupUnmuteAndRedirectButtons(template: template)
|
||||
}
|
||||
template.leadingNavigationBarButtons = [muteButton, redirectButton]
|
||||
} else {
|
||||
template.leadingNavigationBarButtons = [redirectButton]
|
||||
}
|
||||
}
|
||||
|
||||
private class func setupUnmuteAndRedirectButtons(template: CPMapTemplate) {
|
||||
let redirectButton = buildBarButton(type: .redirectRoute) { _ in
|
||||
let listTemplate = ListTemplateBuilder.buildListTemplate(for: .history)
|
||||
CarPlayService.shared.pushTemplate(listTemplate, animated: true)
|
||||
}
|
||||
if MWMTextToSpeech.isTTSEnabled() {
|
||||
let unmuteButton = buildBarButton(type: .unmute) { _ in
|
||||
MWMTextToSpeech.tts().active = true
|
||||
setupMuteAndRedirectButtons(template: template)
|
||||
}
|
||||
template.leadingNavigationBarButtons = [unmuteButton, redirectButton]
|
||||
} else {
|
||||
template.leadingNavigationBarButtons = [redirectButton]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CPMapButton builder
|
||||
private class func buildMapButton(type: MapButtonType, action: ((CPMapButton) -> Void)?) -> CPMapButton {
|
||||
let button = CPMapButton(handler: action)
|
||||
switch type {
|
||||
case .startPanning:
|
||||
button.image = UIImage(systemName: "arrow.up.and.down.and.arrow.left.and.right")
|
||||
case .zoomIn:
|
||||
button.image = UIImage(systemName: "plus")
|
||||
case .zoomOut:
|
||||
button.image = UIImage(systemName: "minus")
|
||||
}
|
||||
// Remove code below once Apple has fixed its issue with the button background
|
||||
if #unavailable(iOS 26) {
|
||||
switch type {
|
||||
case .startPanning:
|
||||
button.focusedImage = UIImage(systemName: "smallcircle.filled.circle.fill")
|
||||
case .zoomIn:
|
||||
button.focusedImage = UIImage(systemName: "plus.circle.fill")
|
||||
case .zoomOut:
|
||||
button.focusedImage = UIImage(systemName: "minus.circle.fill")
|
||||
}
|
||||
}
|
||||
return button
|
||||
}
|
||||
|
||||
// MARK: - CPBarButton builder
|
||||
private class func buildBarButton(type: BarButtonType, action: ((CPBarButton) -> Void)?) -> CPBarButton {
|
||||
switch type {
|
||||
case .dismissPaning:
|
||||
return CPBarButton(title: L("done"), handler: action)
|
||||
case .destination:
|
||||
return CPBarButton(title: L("pick_destination"), handler: action)
|
||||
case .recenter:
|
||||
return CPBarButton(title: L("follow_my_position"), handler: action)
|
||||
case .settings:
|
||||
return CPBarButton(image: UIImage(systemName: "gearshape.fill")!, handler: action)
|
||||
case .mute:
|
||||
return CPBarButton(image: UIImage(systemName: "speaker.wave.3")!, handler: action)
|
||||
case .unmute:
|
||||
return CPBarButton(image: UIImage(systemName: "speaker.slash")!, handler: action)
|
||||
case .redirectRoute:
|
||||
return CPBarButton(image: UIImage(named: "ic_carplay_redirect_route")!, handler: action)
|
||||
case .endRoute:
|
||||
return CPBarButton(title: L("navigation_stop_button").capitalized, handler: action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import CarPlay
|
||||
|
||||
final class SearchTemplateBuilder {
|
||||
// MARK: - CPSearchTemplate builder
|
||||
class func buildSearchTemplate() -> CPSearchTemplate {
|
||||
let template = CPSearchTemplate()
|
||||
return template
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
import CarPlay
|
||||
|
||||
final class SettingsTemplateBuilder {
|
||||
// MARK: - CPGridTemplate builder
|
||||
class func buildGridTemplate() -> CPGridTemplate {
|
||||
let actions = SettingsTemplateBuilder.buildGridButtons()
|
||||
let gridTemplate = CPGridTemplate(title: L("settings"),
|
||||
gridButtons: actions)
|
||||
|
||||
return gridTemplate
|
||||
}
|
||||
|
||||
private class func buildGridButtons() -> [CPGridButton] {
|
||||
let options = RoutingOptions()
|
||||
return [createTollButton(options: options),
|
||||
createUnpavedButton(options: options),
|
||||
createPavedButton(options: options),
|
||||
createMotorwayButton(options: options),
|
||||
createFerryButton(options: options),
|
||||
createStepsButton(options: options),
|
||||
createSpeedcamButton()]
|
||||
}
|
||||
|
||||
// MARK: - CPGridButton builders
|
||||
private class func createTollButton(options: RoutingOptions) -> CPGridButton {
|
||||
var tollIconName = "tolls.circle"
|
||||
if options.avoidToll { tollIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: tollIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let tollButton = CPGridButton(titleVariants: [L("avoid_tolls")], image: image) { _ in
|
||||
options.avoidToll = !options.avoidToll
|
||||
options.save()
|
||||
CarPlayService.shared.updateRouteAfterChangingSettings()
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
return tollButton
|
||||
}
|
||||
|
||||
private class func createUnpavedButton(options: RoutingOptions) -> CPGridButton {
|
||||
var unpavedIconName = "unpaved.circle"
|
||||
if options.avoidDirty && !options.avoidPaved { unpavedIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: unpavedIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let unpavedButton = CPGridButton(titleVariants: [L("avoid_unpaved")], image: image) { _ in
|
||||
options.avoidDirty = !options.avoidDirty
|
||||
if options.avoidDirty {
|
||||
options.avoidPaved = false
|
||||
}
|
||||
options.save()
|
||||
CarPlayService.shared.updateRouteAfterChangingSettings()
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
unpavedButton.isEnabled = !options.avoidPaved
|
||||
return unpavedButton
|
||||
}
|
||||
|
||||
private class func createPavedButton(options: RoutingOptions) -> CPGridButton {
|
||||
var pavedIconName = "paved.circle"
|
||||
if options.avoidPaved && !options.avoidDirty { pavedIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: pavedIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let pavedButton = CPGridButton(titleVariants: [L("avoid_paved")], image: image) { _ in
|
||||
options.avoidPaved = !options.avoidPaved
|
||||
if options.avoidPaved {
|
||||
options.avoidDirty = false
|
||||
}
|
||||
options.save()
|
||||
CarPlayService.shared.updateRouteAfterChangingSettings()
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
pavedButton.isEnabled = !options.avoidDirty
|
||||
return pavedButton
|
||||
}
|
||||
|
||||
private class func createMotorwayButton(options: RoutingOptions) -> CPGridButton {
|
||||
var motorwayIconName = "motorways.circle"
|
||||
if options.avoidMotorway { motorwayIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: motorwayIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let motorwayButton = CPGridButton(titleVariants: [L("avoid_motorways")], image: image) { _ in
|
||||
options.avoidMotorway = !options.avoidMotorway
|
||||
options.save()
|
||||
CarPlayService.shared.updateRouteAfterChangingSettings()
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
return motorwayButton
|
||||
}
|
||||
|
||||
private class func createFerryButton(options: RoutingOptions) -> CPGridButton {
|
||||
var ferryIconName = "ferries.circle"
|
||||
if options.avoidFerry { ferryIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: ferryIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let ferryButton = CPGridButton(titleVariants: [L("avoid_ferry")], image: image) { _ in
|
||||
options.avoidFerry = !options.avoidFerry
|
||||
options.save()
|
||||
CarPlayService.shared.updateRouteAfterChangingSettings()
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
return ferryButton
|
||||
}
|
||||
|
||||
private class func createStepsButton(options: RoutingOptions) -> CPGridButton {
|
||||
var stepsIconName = "steps.circle"
|
||||
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 = "speedcamera"
|
||||
let isSpeedCamActivated = CarPlayService.shared.isSpeedCamActivated
|
||||
if !isSpeedCamActivated { speedcamIconName += ".slash" }
|
||||
let configuration = UIImage.SymbolConfiguration(textStyle: .title1)
|
||||
var image = UIImage(named: speedcamIconName, in: nil, with: configuration)!
|
||||
if #unavailable(iOS 26) {
|
||||
image = image.withTintColor(.white, renderingMode: .alwaysTemplate)
|
||||
image = UIImage(data: image.pngData()!)!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
let speedButton = CPGridButton(titleVariants: [L("speedcams_alert_title_carplay_1"), L("speedcams_alert_title_carplay_2")], image: image) { _ in
|
||||
CarPlayService.shared.isSpeedCamActivated = !isSpeedCamActivated
|
||||
CarPlayService.shared.popTemplate(animated: true)
|
||||
}
|
||||
return speedButton
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue