diff --git a/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsBaseNavigationView.kt b/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsBaseNavigationView.kt index 95679ae2..fb6400cf 100644 --- a/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsBaseNavigationView.kt +++ b/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsBaseNavigationView.kt @@ -18,6 +18,7 @@ package com.google.maps.flutter.navigation import com.google.android.libraries.navigation.ForceNightMode import com.google.android.libraries.navigation.NavigationView +import com.google.android.libraries.navigation.StylingOptions /** * Base class for map views backed by a [NavigationView] from the Navigation SDK. @@ -45,6 +46,7 @@ abstract class GoogleMapsBaseNavigationView( private var _isTrafficIncidentCardsEnabled: Boolean = true private var _isTrafficPromptsEnabled: Boolean = true private var _isNavigationHeaderEnabled: Boolean = true + private var _navigationHeaderStylingOptions = NavigationHeaderStylingOptionsDto() private var _isNavigationFooterEnabled: Boolean = true private var _isRecenterButtonEnabled: Boolean = true private var _isReportIncidentButtonEnabled: Boolean = true @@ -116,6 +118,48 @@ abstract class GoogleMapsBaseNavigationView( _isNavigationHeaderEnabled = enabled } + fun getNavigationHeaderStylingOptions(): NavigationHeaderStylingOptionsDto { + return _navigationHeaderStylingOptions + } + + fun setNavigationHeaderStylingOptions(stylingOptions: NavigationHeaderStylingOptionsDto) { + val builder = StylingOptions() + + stylingOptions.primaryDayModeBackgroundColor?.let { + builder.primaryDayModeThemeColor(it.toInt()) + } + stylingOptions.secondaryDayModeBackgroundColor?.let { + builder.secondaryDayModeThemeColor(it.toInt()) + } + stylingOptions.primaryNightModeBackgroundColor?.let { + builder.primaryNightModeThemeColor(it.toInt()) + } + stylingOptions.secondaryNightModeBackgroundColor?.let { + builder.secondaryNightModeThemeColor(it.toInt()) + } + stylingOptions.largeManeuverIconColor?.let { builder.headerLargeManeuverIconColor(it.toInt()) } + stylingOptions.smallManeuverIconColor?.let { builder.headerSmallManeuverIconColor(it.toInt()) } + stylingOptions.nextStepTextColor?.let { builder.headerNextStepTextColor(it.toInt()) } + stylingOptions.nextStepTextSize?.let { builder.headerNextStepTextSize(it.toFloat()) } + stylingOptions.distanceValueTextColor?.let { builder.headerDistanceValueTextColor(it.toInt()) } + stylingOptions.distanceUnitsTextColor?.let { builder.headerDistanceUnitsTextColor(it.toInt()) } + stylingOptions.distanceValueTextSize?.let { builder.headerDistanceValueTextSize(it.toFloat()) } + stylingOptions.distanceUnitsTextSize?.let { builder.headerDistanceUnitsTextSize(it.toFloat()) } + stylingOptions.instructionsTextColor?.let { builder.headerInstructionsTextColor(it.toInt()) } + stylingOptions.instructionsFirstRowTextSize?.let { + builder.headerInstructionsFirstRowTextSize(it.toFloat()) + } + stylingOptions.instructionsSecondRowTextSize?.let { + builder.headerInstructionsSecondRowTextSize(it.toFloat()) + } + stylingOptions.guidanceRecommendedLaneColor?.let { + builder.headerGuidanceRecommendedLaneColor(it.toInt()) + } + + navigationView.setStylingOptions(builder) + _navigationHeaderStylingOptions = stylingOptions + } + fun isNavigationFooterEnabled(): Boolean { return _isNavigationFooterEnabled } diff --git a/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsViewMessageHandler.kt b/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsViewMessageHandler.kt index f8a310e6..0993e061 100644 --- a/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsViewMessageHandler.kt +++ b/android/src/main/kotlin/com/google/maps/flutter/navigation/GoogleMapsViewMessageHandler.kt @@ -320,6 +320,17 @@ class GoogleMapsViewMessageHandler(private val viewRegistry: GoogleMapsViewRegis getNavigationView(viewId.toInt()).setNavigationHeaderEnabled(enabled) } + override fun getNavigationHeaderStylingOptions(viewId: Long): NavigationHeaderStylingOptionsDto { + return getNavigationView(viewId.toInt()).getNavigationHeaderStylingOptions() + } + + override fun setNavigationHeaderStylingOptions( + viewId: Long, + stylingOptions: NavigationHeaderStylingOptionsDto, + ) { + getNavigationView(viewId.toInt()).setNavigationHeaderStylingOptions(stylingOptions) + } + override fun isNavigationFooterEnabled(viewId: Long): Boolean { return getNavigationView(viewId.toInt()).isNavigationFooterEnabled() } diff --git a/android/src/main/kotlin/com/google/maps/flutter/navigation/messages.g.kt b/android/src/main/kotlin/com/google/maps/flutter/navigation/messages.g.kt index 41d95081..30697079 100644 --- a/android/src/main/kotlin/com/google/maps/flutter/navigation/messages.g.kt +++ b/android/src/main/kotlin/com/google/maps/flutter/navigation/messages.g.kt @@ -1648,6 +1648,107 @@ data class MapPaddingDto(val top: Long, val left: Long, val bottom: Long, val ri override fun hashCode(): Int = toList().hashCode() } +/** + * Navigation header styling options. + * + * All color values are 32-bit ARGB integers (format: 0xAARRGGBB). All text size values are logical + * pixels. Any null value resets that specific field to the native SDK default. + * + * Text size fields are currently Android only and are ignored on iOS. + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class NavigationHeaderStylingOptionsDto( + val primaryDayModeBackgroundColor: Long? = null, + val secondaryDayModeBackgroundColor: Long? = null, + val primaryNightModeBackgroundColor: Long? = null, + val secondaryNightModeBackgroundColor: Long? = null, + val largeManeuverIconColor: Long? = null, + val smallManeuverIconColor: Long? = null, + val nextStepTextColor: Long? = null, + val nextStepTextSize: Double? = null, + val distanceValueTextColor: Long? = null, + val distanceUnitsTextColor: Long? = null, + val distanceValueTextSize: Double? = null, + val distanceUnitsTextSize: Double? = null, + val instructionsTextColor: Long? = null, + val instructionsFirstRowTextSize: Double? = null, + val instructionsSecondRowTextSize: Double? = null, + val guidanceRecommendedLaneColor: Long? = null, +) { + companion object { + fun fromList(pigeonVar_list: List): NavigationHeaderStylingOptionsDto { + val primaryDayModeBackgroundColor = pigeonVar_list[0] as Long? + val secondaryDayModeBackgroundColor = pigeonVar_list[1] as Long? + val primaryNightModeBackgroundColor = pigeonVar_list[2] as Long? + val secondaryNightModeBackgroundColor = pigeonVar_list[3] as Long? + val largeManeuverIconColor = pigeonVar_list[4] as Long? + val smallManeuverIconColor = pigeonVar_list[5] as Long? + val nextStepTextColor = pigeonVar_list[6] as Long? + val nextStepTextSize = pigeonVar_list[7] as Double? + val distanceValueTextColor = pigeonVar_list[8] as Long? + val distanceUnitsTextColor = pigeonVar_list[9] as Long? + val distanceValueTextSize = pigeonVar_list[10] as Double? + val distanceUnitsTextSize = pigeonVar_list[11] as Double? + val instructionsTextColor = pigeonVar_list[12] as Long? + val instructionsFirstRowTextSize = pigeonVar_list[13] as Double? + val instructionsSecondRowTextSize = pigeonVar_list[14] as Double? + val guidanceRecommendedLaneColor = pigeonVar_list[15] as Long? + return NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor, + largeManeuverIconColor, + smallManeuverIconColor, + nextStepTextColor, + nextStepTextSize, + distanceValueTextColor, + distanceUnitsTextColor, + distanceValueTextSize, + distanceUnitsTextSize, + instructionsTextColor, + instructionsFirstRowTextSize, + instructionsSecondRowTextSize, + guidanceRecommendedLaneColor, + ) + } + } + + fun toList(): List { + return listOf( + primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor, + largeManeuverIconColor, + smallManeuverIconColor, + nextStepTextColor, + nextStepTextSize, + distanceValueTextColor, + distanceUnitsTextColor, + distanceValueTextSize, + distanceUnitsTextSize, + instructionsTextColor, + instructionsFirstRowTextSize, + instructionsSecondRowTextSize, + guidanceRecommendedLaneColor, + ) + } + + override fun equals(other: Any?): Boolean { + if (other !is NavigationHeaderStylingOptionsDto) { + return false + } + if (this === other) { + return true + } + return MessagesPigeonUtils.deepEquals(toList(), other.toList()) + } + + override fun hashCode(): Int = toList().hashCode() +} + /** Generated class from Pigeon that represents data sent in messages. */ data class RouteTokenOptionsDto(val routeToken: String, val travelMode: TravelModeDto? = null) { companion object { @@ -2785,87 +2886,92 @@ private open class messagesPigeonCodec : StandardMessageCodec() { return (readValue(buffer) as? List)?.let { MapPaddingDto.fromList(it) } } 179.toByte() -> { - return (readValue(buffer) as? List)?.let { RouteTokenOptionsDto.fromList(it) } + return (readValue(buffer) as? List)?.let { + NavigationHeaderStylingOptionsDto.fromList(it) + } } 180.toByte() -> { - return (readValue(buffer) as? List)?.let { DestinationsDto.fromList(it) } + return (readValue(buffer) as? List)?.let { RouteTokenOptionsDto.fromList(it) } } 181.toByte() -> { - return (readValue(buffer) as? List)?.let { RoutingOptionsDto.fromList(it) } + return (readValue(buffer) as? List)?.let { DestinationsDto.fromList(it) } } 182.toByte() -> { - return (readValue(buffer) as? List)?.let { NavigationDisplayOptionsDto.fromList(it) } + return (readValue(buffer) as? List)?.let { RoutingOptionsDto.fromList(it) } } 183.toByte() -> { - return (readValue(buffer) as? List)?.let { NavigationWaypointDto.fromList(it) } + return (readValue(buffer) as? List)?.let { NavigationDisplayOptionsDto.fromList(it) } } 184.toByte() -> { + return (readValue(buffer) as? List)?.let { NavigationWaypointDto.fromList(it) } + } + 185.toByte() -> { return (readValue(buffer) as? List)?.let { ContinueToNextDestinationResponseDto.fromList(it) } } - 185.toByte() -> { + 186.toByte() -> { return (readValue(buffer) as? List)?.let { NavigationTimeAndDistanceDto.fromList(it) } } - 186.toByte() -> { + 187.toByte() -> { return (readValue(buffer) as? List)?.let { NavigationAudioGuidanceSettingsDto.fromList(it) } } - 187.toByte() -> { + 188.toByte() -> { return (readValue(buffer) as? List)?.let { SimulationOptionsDto.fromList(it) } } - 188.toByte() -> { + 189.toByte() -> { return (readValue(buffer) as? List)?.let { LatLngDto.fromList(it) } } - 189.toByte() -> { + 190.toByte() -> { return (readValue(buffer) as? List)?.let { LatLngBoundsDto.fromList(it) } } - 190.toByte() -> { + 191.toByte() -> { return (readValue(buffer) as? List)?.let { SpeedingUpdatedEventDto.fromList(it) } } - 191.toByte() -> { + 192.toByte() -> { return (readValue(buffer) as? List)?.let { GpsAvailabilityChangeEventDto.fromList(it) } } - 192.toByte() -> { + 193.toByte() -> { return (readValue(buffer) as? List)?.let { SpeedAlertOptionsThresholdPercentageDto.fromList(it) } } - 193.toByte() -> { + 194.toByte() -> { return (readValue(buffer) as? List)?.let { SpeedAlertOptionsDto.fromList(it) } } - 194.toByte() -> { + 195.toByte() -> { return (readValue(buffer) as? List)?.let { RouteSegmentTrafficDataRoadStretchRenderingDataDto.fromList(it) } } - 195.toByte() -> { + 196.toByte() -> { return (readValue(buffer) as? List)?.let { RouteSegmentTrafficDataDto.fromList(it) } } - 196.toByte() -> { + 197.toByte() -> { return (readValue(buffer) as? List)?.let { RouteSegmentDto.fromList(it) } } - 197.toByte() -> { + 198.toByte() -> { return (readValue(buffer) as? List)?.let { LaneDirectionDto.fromList(it) } } - 198.toByte() -> { + 199.toByte() -> { return (readValue(buffer) as? List)?.let { LaneDto.fromList(it) } } - 199.toByte() -> { + 200.toByte() -> { return (readValue(buffer) as? List)?.let { StepInfoDto.fromList(it) } } - 200.toByte() -> { + 201.toByte() -> { return (readValue(buffer) as? List)?.let { NavInfoDto.fromList(it) } } - 201.toByte() -> { + 202.toByte() -> { return (readValue(buffer) as? List)?.let { TermsAndConditionsUIParamsDto.fromList(it) } } - 202.toByte() -> { + 203.toByte() -> { return (readValue(buffer) as? List)?.let { StepImageGenerationOptionsDto.fromList(it) } @@ -3076,102 +3182,106 @@ private open class messagesPigeonCodec : StandardMessageCodec() { stream.write(178) writeValue(stream, value.toList()) } - is RouteTokenOptionsDto -> { + is NavigationHeaderStylingOptionsDto -> { stream.write(179) writeValue(stream, value.toList()) } - is DestinationsDto -> { + is RouteTokenOptionsDto -> { stream.write(180) writeValue(stream, value.toList()) } - is RoutingOptionsDto -> { + is DestinationsDto -> { stream.write(181) writeValue(stream, value.toList()) } - is NavigationDisplayOptionsDto -> { + is RoutingOptionsDto -> { stream.write(182) writeValue(stream, value.toList()) } - is NavigationWaypointDto -> { + is NavigationDisplayOptionsDto -> { stream.write(183) writeValue(stream, value.toList()) } - is ContinueToNextDestinationResponseDto -> { + is NavigationWaypointDto -> { stream.write(184) writeValue(stream, value.toList()) } - is NavigationTimeAndDistanceDto -> { + is ContinueToNextDestinationResponseDto -> { stream.write(185) writeValue(stream, value.toList()) } - is NavigationAudioGuidanceSettingsDto -> { + is NavigationTimeAndDistanceDto -> { stream.write(186) writeValue(stream, value.toList()) } - is SimulationOptionsDto -> { + is NavigationAudioGuidanceSettingsDto -> { stream.write(187) writeValue(stream, value.toList()) } - is LatLngDto -> { + is SimulationOptionsDto -> { stream.write(188) writeValue(stream, value.toList()) } - is LatLngBoundsDto -> { + is LatLngDto -> { stream.write(189) writeValue(stream, value.toList()) } - is SpeedingUpdatedEventDto -> { + is LatLngBoundsDto -> { stream.write(190) writeValue(stream, value.toList()) } - is GpsAvailabilityChangeEventDto -> { + is SpeedingUpdatedEventDto -> { stream.write(191) writeValue(stream, value.toList()) } - is SpeedAlertOptionsThresholdPercentageDto -> { + is GpsAvailabilityChangeEventDto -> { stream.write(192) writeValue(stream, value.toList()) } - is SpeedAlertOptionsDto -> { + is SpeedAlertOptionsThresholdPercentageDto -> { stream.write(193) writeValue(stream, value.toList()) } - is RouteSegmentTrafficDataRoadStretchRenderingDataDto -> { + is SpeedAlertOptionsDto -> { stream.write(194) writeValue(stream, value.toList()) } - is RouteSegmentTrafficDataDto -> { + is RouteSegmentTrafficDataRoadStretchRenderingDataDto -> { stream.write(195) writeValue(stream, value.toList()) } - is RouteSegmentDto -> { + is RouteSegmentTrafficDataDto -> { stream.write(196) writeValue(stream, value.toList()) } - is LaneDirectionDto -> { + is RouteSegmentDto -> { stream.write(197) writeValue(stream, value.toList()) } - is LaneDto -> { + is LaneDirectionDto -> { stream.write(198) writeValue(stream, value.toList()) } - is StepInfoDto -> { + is LaneDto -> { stream.write(199) writeValue(stream, value.toList()) } - is NavInfoDto -> { + is StepInfoDto -> { stream.write(200) writeValue(stream, value.toList()) } - is TermsAndConditionsUIParamsDto -> { + is NavInfoDto -> { stream.write(201) writeValue(stream, value.toList()) } - is StepImageGenerationOptionsDto -> { + is TermsAndConditionsUIParamsDto -> { stream.write(202) writeValue(stream, value.toList()) } + is StepImageGenerationOptionsDto -> { + stream.write(203) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -3256,6 +3366,13 @@ interface MapViewApi { fun setNavigationHeaderEnabled(viewId: Long, enabled: Boolean) + fun getNavigationHeaderStylingOptions(viewId: Long): NavigationHeaderStylingOptionsDto + + fun setNavigationHeaderStylingOptions( + viewId: Long, + stylingOptions: NavigationHeaderStylingOptionsDto, + ) + fun isNavigationFooterEnabled(viewId: Long): Boolean fun setNavigationFooterEnabled(viewId: Long, enabled: Boolean) @@ -3775,6 +3892,54 @@ interface MapViewApi { channel.setMessageHandler(null) } } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions$separatedMessageChannelSuffix", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val viewIdArg = args[0] as Long + val wrapped: List = + try { + listOf(api.getNavigationHeaderStylingOptions(viewIdArg)) + } catch (exception: Throwable) { + MessagesPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions$separatedMessageChannelSuffix", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val viewIdArg = args[0] as Long + val stylingOptionsArg = args[1] as NavigationHeaderStylingOptionsDto + val wrapped: List = + try { + api.setNavigationHeaderStylingOptions(viewIdArg, stylingOptionsArg) + listOf(null) + } catch (exception: Throwable) { + MessagesPigeonUtils.wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel( diff --git a/example/lib/pages/navigation.dart b/example/lib/pages/navigation.dart index f8c87c8f..de5d44e3 100644 --- a/example/lib/pages/navigation.dart +++ b/example/lib/pages/navigation.dart @@ -108,6 +108,8 @@ class _NavigationPageState extends ExamplePageState { IndoorBuilding? _focusedIndoorBuilding; bool _navigationHeaderEnabled = true; + NavigationHeaderStylingOptions _navigationHeaderStylingOptions = + const NavigationHeaderStylingOptions(); bool _navigationFooterEnabled = true; bool _navigationTripProgressBarEnabled = true; bool _navigationUIEnabled = true; @@ -802,6 +804,8 @@ class _NavigationPageState extends ExamplePageState { if (_navigationViewController != null) { final bool navigationHeaderEnabled = await _navigationViewController! .isNavigationHeaderEnabled(); + final NavigationHeaderStylingOptions navigationHeaderStylingOptions = + await _navigationViewController!.getNavigationHeaderStylingOptions(); final bool navigationFooterEnabled = await _navigationViewController! .isNavigationFooterEnabled(); final bool navigationTripProgressBarEnabled = @@ -830,6 +834,7 @@ class _NavigationPageState extends ExamplePageState { setState(() { _navigationHeaderEnabled = navigationHeaderEnabled; + _navigationHeaderStylingOptions = navigationHeaderStylingOptions; _navigationFooterEnabled = navigationFooterEnabled; _navigationTripProgressBarEnabled = navigationTripProgressBarEnabled; _navigationUIEnabled = navigationUIEnabled; @@ -846,6 +851,21 @@ class _NavigationPageState extends ExamplePageState { } } + Future _applyNavigationHeaderStyling( + NavigationHeaderStylingOptions stylingOptions, + ) async { + if (_navigationViewController == null) { + return; + } + await _navigationViewController!.setNavigationHeaderStylingOptions( + stylingOptions, + ); + if (!mounted) return; + setState(() { + _navigationHeaderStylingOptions = stylingOptions; + }); + } + void _onRecenterButtonClickedEvent( NavigationViewRecenterButtonClickedEvent msg, ) { @@ -2135,6 +2155,86 @@ class _NavigationPageState extends ExamplePageState { }); }, ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Header styling example', + style: Theme.of(context).textTheme.titleSmall, + ), + const SizedBox(height: 8), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + ElevatedButton( + onPressed: () => _applyNavigationHeaderStyling( + const NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: Colors.blue, + secondaryDayModeBackgroundColor: Colors.red, + primaryNightModeBackgroundColor: Colors.black, + secondaryNightModeBackgroundColor: + Colors.blueGrey, + ), + ), + child: const Text('Apply background colors'), + ), + ElevatedButton( + onPressed: () => _applyNavigationHeaderStyling( + const NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: Colors.indigo, + secondaryDayModeBackgroundColor: + Colors.deepPurple, + primaryNightModeBackgroundColor: Colors.black, + secondaryNightModeBackgroundColor: + Colors.indigo, + largeManeuverIconColor: Colors.orange, + smallManeuverIconColor: Colors.amber, + nextStepTextColor: Colors.yellow, + nextStepTextSize: 18, + distanceValueTextColor: Colors.white, + distanceUnitsTextColor: Colors.white70, + distanceValueTextSize: 24, + distanceUnitsTextSize: 16, + instructionsTextColor: Colors.cyanAccent, + instructionsFirstRowTextSize: 28, + instructionsSecondRowTextSize: 22, + guidanceRecommendedLaneColor: + Colors.lightGreenAccent, + ), + ), + child: const Text('Apply full styling sample'), + ), + ElevatedButton( + onPressed: () => _applyNavigationHeaderStyling( + const NavigationHeaderStylingOptions(), + ), + child: const Text('Reset header styling'), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Current primary day color: ' + '${_navigationHeaderStylingOptions.primaryDayModeBackgroundColor ?? 'default'}', + ), + Text( + 'Current large maneuver icon color: ' + '${_navigationHeaderStylingOptions.largeManeuverIconColor ?? 'default'}', + ), + Text( + 'Current next-step text size: ' + '${_navigationHeaderStylingOptions.nextStepTextSize ?? 'default'} ' + '(Android only)', + ), + ], + ), + ), ExampleSwitch( title: 'Enable footer', initialValue: _navigationFooterEnabled, diff --git a/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationView.swift b/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationView.swift index effa63e9..78e14690 100644 --- a/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationView.swift +++ b/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationView.swift @@ -619,6 +619,57 @@ public class GoogleMapsNavigationView: NSObject, FlutterPlatformView, ViewSettle _mapView.settings.isNavigationHeaderEnabled = enabled } + func getNavigationHeaderStylingOptions() -> NavigationHeaderStylingOptionsDto { + NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor: _mapView.settings.navigationHeaderPrimaryBackgroundColor? + .toRgb(), + secondaryDayModeBackgroundColor: _mapView.settings.navigationHeaderSecondaryBackgroundColor? + .toRgb(), + primaryNightModeBackgroundColor: _mapView.settings + .navigationHeaderPrimaryBackgroundColorNightMode?.toRgb(), + secondaryNightModeBackgroundColor: _mapView.settings + .navigationHeaderSecondaryBackgroundColorNightMode?.toRgb(), + largeManeuverIconColor: _mapView.settings.navigationHeaderLargeManeuverIconColor? + .toRgb(), + smallManeuverIconColor: _mapView.settings.navigationHeaderSmallManeuverIconColor? + .toRgb(), + nextStepTextColor: _mapView.settings.navigationHeaderNextStepTextColor?.toRgb(), + distanceValueTextColor: _mapView.settings.navigationHeaderDistanceValueTextColor? + .toRgb(), + distanceUnitsTextColor: _mapView.settings.navigationHeaderDistanceUnitsTextColor? + .toRgb(), + instructionsTextColor: _mapView.settings.navigationHeaderInstructionsTextColor? + .toRgb(), + guidanceRecommendedLaneColor: _mapView.settings + .navigationHeaderGuidanceRecommendedLaneColor?.toRgb() + ) + } + + func setNavigationHeaderStylingOptions(_ stylingOptions: NavigationHeaderStylingOptionsDto) { + _mapView.settings.navigationHeaderPrimaryBackgroundColor = stylingOptions + .primaryDayModeBackgroundColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderSecondaryBackgroundColor = stylingOptions + .secondaryDayModeBackgroundColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderPrimaryBackgroundColorNightMode = stylingOptions + .primaryNightModeBackgroundColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderSecondaryBackgroundColorNightMode = stylingOptions + .secondaryNightModeBackgroundColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderLargeManeuverIconColor = stylingOptions + .largeManeuverIconColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderSmallManeuverIconColor = stylingOptions + .smallManeuverIconColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderNextStepTextColor = stylingOptions + .nextStepTextColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderDistanceValueTextColor = stylingOptions + .distanceValueTextColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderDistanceUnitsTextColor = stylingOptions + .distanceUnitsTextColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderInstructionsTextColor = stylingOptions + .instructionsTextColor.map { UIColor(from: $0) } + _mapView.settings.navigationHeaderGuidanceRecommendedLaneColor = stylingOptions + .guidanceRecommendedLaneColor.map { UIColor(from: $0) } + } + func isNavigationFooterEnabled() -> Bool { _mapView.settings.isNavigationFooterEnabled } diff --git a/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationViewMessageHandler.swift b/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationViewMessageHandler.swift index 12be8479..028f5725 100644 --- a/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationViewMessageHandler.swift +++ b/ios/google_navigation_flutter/Sources/google_navigation_flutter/GoogleMapsNavigationViewMessageHandler.swift @@ -358,6 +358,18 @@ class GoogleMapsNavigationViewMessageHandler: MapViewApi { try getView(viewId).setNavigationHeaderEnabled(enabled) } + func getNavigationHeaderStylingOptions(viewId: Int64) throws -> NavigationHeaderStylingOptionsDto + { + try getView(viewId).getNavigationHeaderStylingOptions() + } + + func setNavigationHeaderStylingOptions( + viewId: Int64, + stylingOptions: NavigationHeaderStylingOptionsDto + ) throws { + try getView(viewId).setNavigationHeaderStylingOptions(stylingOptions) + } + func setNavigationFooterEnabled(viewId: Int64, enabled: Bool) throws { try getView(viewId).setNavigationFooterEnabled(enabled) } diff --git a/ios/google_navigation_flutter/Sources/google_navigation_flutter/messages.g.swift b/ios/google_navigation_flutter/Sources/google_navigation_flutter/messages.g.swift index 15ff33e1..35bb5442 100644 --- a/ios/google_navigation_flutter/Sources/google_navigation_flutter/messages.g.swift +++ b/ios/google_navigation_flutter/Sources/google_navigation_flutter/messages.g.swift @@ -1499,6 +1499,101 @@ struct MapPaddingDto: Hashable { } } +/// Navigation header styling options. +/// +/// All color values are 32-bit ARGB integers (format: 0xAARRGGBB). +/// All text size values are logical pixels. +/// Any null value resets that specific field to the native SDK default. +/// +/// Text size fields are currently Android only and are ignored on iOS. +/// +/// Generated class from Pigeon that represents data sent in messages. +struct NavigationHeaderStylingOptionsDto: Hashable { + var primaryDayModeBackgroundColor: Int64? = nil + var secondaryDayModeBackgroundColor: Int64? = nil + var primaryNightModeBackgroundColor: Int64? = nil + var secondaryNightModeBackgroundColor: Int64? = nil + var largeManeuverIconColor: Int64? = nil + var smallManeuverIconColor: Int64? = nil + var nextStepTextColor: Int64? = nil + var nextStepTextSize: Double? = nil + var distanceValueTextColor: Int64? = nil + var distanceUnitsTextColor: Int64? = nil + var distanceValueTextSize: Double? = nil + var distanceUnitsTextSize: Double? = nil + var instructionsTextColor: Int64? = nil + var instructionsFirstRowTextSize: Double? = nil + var instructionsSecondRowTextSize: Double? = nil + var guidanceRecommendedLaneColor: Int64? = nil + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> NavigationHeaderStylingOptionsDto? { + let primaryDayModeBackgroundColor: Int64? = nilOrValue(pigeonVar_list[0]) + let secondaryDayModeBackgroundColor: Int64? = nilOrValue(pigeonVar_list[1]) + let primaryNightModeBackgroundColor: Int64? = nilOrValue(pigeonVar_list[2]) + let secondaryNightModeBackgroundColor: Int64? = nilOrValue(pigeonVar_list[3]) + let largeManeuverIconColor: Int64? = nilOrValue(pigeonVar_list[4]) + let smallManeuverIconColor: Int64? = nilOrValue(pigeonVar_list[5]) + let nextStepTextColor: Int64? = nilOrValue(pigeonVar_list[6]) + let nextStepTextSize: Double? = nilOrValue(pigeonVar_list[7]) + let distanceValueTextColor: Int64? = nilOrValue(pigeonVar_list[8]) + let distanceUnitsTextColor: Int64? = nilOrValue(pigeonVar_list[9]) + let distanceValueTextSize: Double? = nilOrValue(pigeonVar_list[10]) + let distanceUnitsTextSize: Double? = nilOrValue(pigeonVar_list[11]) + let instructionsTextColor: Int64? = nilOrValue(pigeonVar_list[12]) + let instructionsFirstRowTextSize: Double? = nilOrValue(pigeonVar_list[13]) + let instructionsSecondRowTextSize: Double? = nilOrValue(pigeonVar_list[14]) + let guidanceRecommendedLaneColor: Int64? = nilOrValue(pigeonVar_list[15]) + + return NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor: primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor: secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor: primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor: secondaryNightModeBackgroundColor, + largeManeuverIconColor: largeManeuverIconColor, + smallManeuverIconColor: smallManeuverIconColor, + nextStepTextColor: nextStepTextColor, + nextStepTextSize: nextStepTextSize, + distanceValueTextColor: distanceValueTextColor, + distanceUnitsTextColor: distanceUnitsTextColor, + distanceValueTextSize: distanceValueTextSize, + distanceUnitsTextSize: distanceUnitsTextSize, + instructionsTextColor: instructionsTextColor, + instructionsFirstRowTextSize: instructionsFirstRowTextSize, + instructionsSecondRowTextSize: instructionsSecondRowTextSize, + guidanceRecommendedLaneColor: guidanceRecommendedLaneColor + ) + } + func toList() -> [Any?] { + return [ + primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor, + largeManeuverIconColor, + smallManeuverIconColor, + nextStepTextColor, + nextStepTextSize, + distanceValueTextColor, + distanceUnitsTextColor, + distanceValueTextSize, + distanceUnitsTextSize, + instructionsTextColor, + instructionsFirstRowTextSize, + instructionsSecondRowTextSize, + guidanceRecommendedLaneColor, + ] + } + static func == (lhs: NavigationHeaderStylingOptionsDto, rhs: NavigationHeaderStylingOptionsDto) + -> Bool + { + return deepEqualsmessages(lhs.toList(), rhs.toList()) + } + func hash(into hasher: inout Hasher) { + deepHashmessages(value: toList(), hasher: &hasher) + } +} + /// Generated class from Pigeon that represents data sent in messages. struct RouteTokenOptionsDto: Hashable { var routeToken: String @@ -2631,53 +2726,55 @@ private class MessagesPigeonCodecReader: FlutterStandardReader { case 178: return MapPaddingDto.fromList(self.readValue() as! [Any?]) case 179: - return RouteTokenOptionsDto.fromList(self.readValue() as! [Any?]) + return NavigationHeaderStylingOptionsDto.fromList(self.readValue() as! [Any?]) case 180: - return DestinationsDto.fromList(self.readValue() as! [Any?]) + return RouteTokenOptionsDto.fromList(self.readValue() as! [Any?]) case 181: - return RoutingOptionsDto.fromList(self.readValue() as! [Any?]) + return DestinationsDto.fromList(self.readValue() as! [Any?]) case 182: - return NavigationDisplayOptionsDto.fromList(self.readValue() as! [Any?]) + return RoutingOptionsDto.fromList(self.readValue() as! [Any?]) case 183: - return NavigationWaypointDto.fromList(self.readValue() as! [Any?]) + return NavigationDisplayOptionsDto.fromList(self.readValue() as! [Any?]) case 184: - return ContinueToNextDestinationResponseDto.fromList(self.readValue() as! [Any?]) + return NavigationWaypointDto.fromList(self.readValue() as! [Any?]) case 185: - return NavigationTimeAndDistanceDto.fromList(self.readValue() as! [Any?]) + return ContinueToNextDestinationResponseDto.fromList(self.readValue() as! [Any?]) case 186: - return NavigationAudioGuidanceSettingsDto.fromList(self.readValue() as! [Any?]) + return NavigationTimeAndDistanceDto.fromList(self.readValue() as! [Any?]) case 187: - return SimulationOptionsDto.fromList(self.readValue() as! [Any?]) + return NavigationAudioGuidanceSettingsDto.fromList(self.readValue() as! [Any?]) case 188: - return LatLngDto.fromList(self.readValue() as! [Any?]) + return SimulationOptionsDto.fromList(self.readValue() as! [Any?]) case 189: - return LatLngBoundsDto.fromList(self.readValue() as! [Any?]) + return LatLngDto.fromList(self.readValue() as! [Any?]) case 190: - return SpeedingUpdatedEventDto.fromList(self.readValue() as! [Any?]) + return LatLngBoundsDto.fromList(self.readValue() as! [Any?]) case 191: - return GpsAvailabilityChangeEventDto.fromList(self.readValue() as! [Any?]) + return SpeedingUpdatedEventDto.fromList(self.readValue() as! [Any?]) case 192: - return SpeedAlertOptionsThresholdPercentageDto.fromList(self.readValue() as! [Any?]) + return GpsAvailabilityChangeEventDto.fromList(self.readValue() as! [Any?]) case 193: - return SpeedAlertOptionsDto.fromList(self.readValue() as! [Any?]) + return SpeedAlertOptionsThresholdPercentageDto.fromList(self.readValue() as! [Any?]) case 194: + return SpeedAlertOptionsDto.fromList(self.readValue() as! [Any?]) + case 195: return RouteSegmentTrafficDataRoadStretchRenderingDataDto.fromList( self.readValue() as! [Any?]) - case 195: - return RouteSegmentTrafficDataDto.fromList(self.readValue() as! [Any?]) case 196: - return RouteSegmentDto.fromList(self.readValue() as! [Any?]) + return RouteSegmentTrafficDataDto.fromList(self.readValue() as! [Any?]) case 197: - return LaneDirectionDto.fromList(self.readValue() as! [Any?]) + return RouteSegmentDto.fromList(self.readValue() as! [Any?]) case 198: - return LaneDto.fromList(self.readValue() as! [Any?]) + return LaneDirectionDto.fromList(self.readValue() as! [Any?]) case 199: - return StepInfoDto.fromList(self.readValue() as! [Any?]) + return LaneDto.fromList(self.readValue() as! [Any?]) case 200: - return NavInfoDto.fromList(self.readValue() as! [Any?]) + return StepInfoDto.fromList(self.readValue() as! [Any?]) case 201: - return TermsAndConditionsUIParamsDto.fromList(self.readValue() as! [Any?]) + return NavInfoDto.fromList(self.readValue() as! [Any?]) case 202: + return TermsAndConditionsUIParamsDto.fromList(self.readValue() as! [Any?]) + case 203: return StepImageGenerationOptionsDto.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -2837,78 +2934,81 @@ private class MessagesPigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? MapPaddingDto { super.writeByte(178) super.writeValue(value.toList()) - } else if let value = value as? RouteTokenOptionsDto { + } else if let value = value as? NavigationHeaderStylingOptionsDto { super.writeByte(179) super.writeValue(value.toList()) - } else if let value = value as? DestinationsDto { + } else if let value = value as? RouteTokenOptionsDto { super.writeByte(180) super.writeValue(value.toList()) - } else if let value = value as? RoutingOptionsDto { + } else if let value = value as? DestinationsDto { super.writeByte(181) super.writeValue(value.toList()) - } else if let value = value as? NavigationDisplayOptionsDto { + } else if let value = value as? RoutingOptionsDto { super.writeByte(182) super.writeValue(value.toList()) - } else if let value = value as? NavigationWaypointDto { + } else if let value = value as? NavigationDisplayOptionsDto { super.writeByte(183) super.writeValue(value.toList()) - } else if let value = value as? ContinueToNextDestinationResponseDto { + } else if let value = value as? NavigationWaypointDto { super.writeByte(184) super.writeValue(value.toList()) - } else if let value = value as? NavigationTimeAndDistanceDto { + } else if let value = value as? ContinueToNextDestinationResponseDto { super.writeByte(185) super.writeValue(value.toList()) - } else if let value = value as? NavigationAudioGuidanceSettingsDto { + } else if let value = value as? NavigationTimeAndDistanceDto { super.writeByte(186) super.writeValue(value.toList()) - } else if let value = value as? SimulationOptionsDto { + } else if let value = value as? NavigationAudioGuidanceSettingsDto { super.writeByte(187) super.writeValue(value.toList()) - } else if let value = value as? LatLngDto { + } else if let value = value as? SimulationOptionsDto { super.writeByte(188) super.writeValue(value.toList()) - } else if let value = value as? LatLngBoundsDto { + } else if let value = value as? LatLngDto { super.writeByte(189) super.writeValue(value.toList()) - } else if let value = value as? SpeedingUpdatedEventDto { + } else if let value = value as? LatLngBoundsDto { super.writeByte(190) super.writeValue(value.toList()) - } else if let value = value as? GpsAvailabilityChangeEventDto { + } else if let value = value as? SpeedingUpdatedEventDto { super.writeByte(191) super.writeValue(value.toList()) - } else if let value = value as? SpeedAlertOptionsThresholdPercentageDto { + } else if let value = value as? GpsAvailabilityChangeEventDto { super.writeByte(192) super.writeValue(value.toList()) - } else if let value = value as? SpeedAlertOptionsDto { + } else if let value = value as? SpeedAlertOptionsThresholdPercentageDto { super.writeByte(193) super.writeValue(value.toList()) - } else if let value = value as? RouteSegmentTrafficDataRoadStretchRenderingDataDto { + } else if let value = value as? SpeedAlertOptionsDto { super.writeByte(194) super.writeValue(value.toList()) - } else if let value = value as? RouteSegmentTrafficDataDto { + } else if let value = value as? RouteSegmentTrafficDataRoadStretchRenderingDataDto { super.writeByte(195) super.writeValue(value.toList()) - } else if let value = value as? RouteSegmentDto { + } else if let value = value as? RouteSegmentTrafficDataDto { super.writeByte(196) super.writeValue(value.toList()) - } else if let value = value as? LaneDirectionDto { + } else if let value = value as? RouteSegmentDto { super.writeByte(197) super.writeValue(value.toList()) - } else if let value = value as? LaneDto { + } else if let value = value as? LaneDirectionDto { super.writeByte(198) super.writeValue(value.toList()) - } else if let value = value as? StepInfoDto { + } else if let value = value as? LaneDto { super.writeByte(199) super.writeValue(value.toList()) - } else if let value = value as? NavInfoDto { + } else if let value = value as? StepInfoDto { super.writeByte(200) super.writeValue(value.toList()) - } else if let value = value as? TermsAndConditionsUIParamsDto { + } else if let value = value as? NavInfoDto { super.writeByte(201) super.writeValue(value.toList()) - } else if let value = value as? StepImageGenerationOptionsDto { + } else if let value = value as? TermsAndConditionsUIParamsDto { super.writeByte(202) super.writeValue(value.toList()) + } else if let value = value as? StepImageGenerationOptionsDto { + super.writeByte(203) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -2982,6 +3082,9 @@ protocol MapViewApi { func setNavigationTripProgressBarEnabled(viewId: Int64, enabled: Bool) throws func isNavigationHeaderEnabled(viewId: Int64) throws -> Bool func setNavigationHeaderEnabled(viewId: Int64, enabled: Bool) throws + func getNavigationHeaderStylingOptions(viewId: Int64) throws -> NavigationHeaderStylingOptionsDto + func setNavigationHeaderStylingOptions( + viewId: Int64, stylingOptions: NavigationHeaderStylingOptionsDto) throws func isNavigationFooterEnabled(viewId: Int64) throws -> Bool func setNavigationFooterEnabled(viewId: Int64, enabled: Bool) throws func isRecenterButtonEnabled(viewId: Int64) throws -> Bool @@ -3308,6 +3411,44 @@ class MapViewApiSetup { } else { setNavigationHeaderEnabledChannel.setMessageHandler(nil) } + let getNavigationHeaderStylingOptionsChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getNavigationHeaderStylingOptionsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let viewIdArg = args[0] as! Int64 + do { + let result = try api.getNavigationHeaderStylingOptions(viewId: viewIdArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getNavigationHeaderStylingOptionsChannel.setMessageHandler(nil) + } + let setNavigationHeaderStylingOptionsChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setNavigationHeaderStylingOptionsChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let viewIdArg = args[0] as! Int64 + let stylingOptionsArg = args[1] as! NavigationHeaderStylingOptionsDto + do { + try api.setNavigationHeaderStylingOptions( + viewId: viewIdArg, stylingOptions: stylingOptionsArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + setNavigationHeaderStylingOptionsChannel.setMessageHandler(nil) + } let isNavigationFooterEnabledChannel = FlutterBasicMessageChannel( name: "dev.flutter.pigeon.google_navigation_flutter.MapViewApi.isNavigationFooterEnabled\(channelSuffix)", diff --git a/lib/src/google_maps_navigation_view_controller.dart b/lib/src/google_maps_navigation_view_controller.dart index cbc304a8..f8a7654f 100644 --- a/lib/src/google_maps_navigation_view_controller.dart +++ b/lib/src/google_maps_navigation_view_controller.dart @@ -51,6 +51,25 @@ class GoogleNavigationViewController extends GoogleMapViewController { .isNavigationHeaderEnabled(viewId: getViewId()); } + /// Returns the native navigation header styling options. + Future getNavigationHeaderStylingOptions() { + return GoogleMapsNavigationPlatform.instance.viewAPI + .getNavigationHeaderStylingOptions(viewId: getViewId()); + } + + /// Sets the native navigation header styling options. + /// + /// Any null field resets that specific option to the native SDK default. + Future setNavigationHeaderStylingOptions( + NavigationHeaderStylingOptions stylingOptions, + ) { + return GoogleMapsNavigationPlatform.instance.viewAPI + .setNavigationHeaderStylingOptions( + viewId: getViewId(), + stylingOptions: stylingOptions, + ); + } + /// Enable or disable the navigation header. /// /// By default, the navigation header is enabled. diff --git a/lib/src/method_channel/convert/navigation.dart b/lib/src/method_channel/convert/navigation.dart index 371b7061..f7491e54 100644 --- a/lib/src/method_channel/convert/navigation.dart +++ b/lib/src/method_channel/convert/navigation.dart @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'dart:ui'; + import '../../../google_navigation_flutter.dart'; import '../method_channel.dart'; @@ -220,6 +222,56 @@ extension ConvertContinueToNextDestinationResponseDto ); } +/// [NavigationHeaderStylingOptionsDto] convert extension. +/// @nodoc +extension ConvertNavigationHeaderStylingOptionsDto + on NavigationHeaderStylingOptionsDto { + /// Converts [NavigationHeaderStylingOptionsDto] to [NavigationHeaderStylingOptions]. + NavigationHeaderStylingOptions toNavigationHeaderStylingOptions() { + return NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: primaryDayModeBackgroundColor != null + ? Color(primaryDayModeBackgroundColor!) + : null, + secondaryDayModeBackgroundColor: secondaryDayModeBackgroundColor != null + ? Color(secondaryDayModeBackgroundColor!) + : null, + primaryNightModeBackgroundColor: primaryNightModeBackgroundColor != null + ? Color(primaryNightModeBackgroundColor!) + : null, + secondaryNightModeBackgroundColor: + secondaryNightModeBackgroundColor != null + ? Color(secondaryNightModeBackgroundColor!) + : null, + largeManeuverIconColor: largeManeuverIconColor != null + ? Color(largeManeuverIconColor!) + : null, + smallManeuverIconColor: smallManeuverIconColor != null + ? Color(smallManeuverIconColor!) + : null, + nextStepTextColor: nextStepTextColor != null + ? Color(nextStepTextColor!) + : null, + nextStepTextSize: nextStepTextSize, + distanceValueTextColor: distanceValueTextColor != null + ? Color(distanceValueTextColor!) + : null, + distanceUnitsTextColor: distanceUnitsTextColor != null + ? Color(distanceUnitsTextColor!) + : null, + distanceValueTextSize: distanceValueTextSize, + distanceUnitsTextSize: distanceUnitsTextSize, + instructionsTextColor: instructionsTextColor != null + ? Color(instructionsTextColor!) + : null, + instructionsFirstRowTextSize: instructionsFirstRowTextSize, + instructionsSecondRowTextSize: instructionsSecondRowTextSize, + guidanceRecommendedLaneColor: guidanceRecommendedLaneColor != null + ? Color(guidanceRecommendedLaneColor!) + : null, + ); + } +} + /// [RouteSegmentDto] convert extension. /// @nodoc extension ConvertRouteSegmentDto on RouteSegmentDto { diff --git a/lib/src/method_channel/map_view_api.dart b/lib/src/method_channel/map_view_api.dart index 05dfc59b..65bedcd9 100644 --- a/lib/src/method_channel/map_view_api.dart +++ b/lib/src/method_channel/map_view_api.dart @@ -525,6 +525,24 @@ class MapViewAPIImpl { Future isNavigationHeaderEnabled({required int viewId}) => _viewApi.isNavigationHeaderEnabled(viewId).wrapPlatformException(); + /// Gets the navigation header styling options. + Future getNavigationHeaderStylingOptions({ + required int viewId, + }) async { + final NavigationHeaderStylingOptionsDto stylingOptions = await _viewApi + .getNavigationHeaderStylingOptions(viewId) + .wrapPlatformException(); + return stylingOptions.toNavigationHeaderStylingOptions(); + } + + /// Sets the navigation header styling options. + Future setNavigationHeaderStylingOptions({ + required int viewId, + required NavigationHeaderStylingOptions stylingOptions, + }) => _viewApi + .setNavigationHeaderStylingOptions(viewId, stylingOptions.toDto()) + .wrapPlatformException(); + /// Enable navigation header. Future setNavigationHeaderEnabled({ required int viewId, diff --git a/lib/src/method_channel/messages.g.dart b/lib/src/method_channel/messages.g.dart index 67e109d8..a51c55da 100644 --- a/lib/src/method_channel/messages.g.dart +++ b/lib/src/method_channel/messages.g.dart @@ -1815,6 +1815,130 @@ class MapPaddingDto { int get hashCode => Object.hashAll(_toList()); } +/// Navigation header styling options. +/// +/// All color values are 32-bit ARGB integers (format: 0xAARRGGBB). +/// All text size values are logical pixels. +/// Any null value resets that specific field to the native SDK default. +/// +/// Text size fields are currently Android only and are ignored on iOS. +class NavigationHeaderStylingOptionsDto { + NavigationHeaderStylingOptionsDto({ + this.primaryDayModeBackgroundColor, + this.secondaryDayModeBackgroundColor, + this.primaryNightModeBackgroundColor, + this.secondaryNightModeBackgroundColor, + this.largeManeuverIconColor, + this.smallManeuverIconColor, + this.nextStepTextColor, + this.nextStepTextSize, + this.distanceValueTextColor, + this.distanceUnitsTextColor, + this.distanceValueTextSize, + this.distanceUnitsTextSize, + this.instructionsTextColor, + this.instructionsFirstRowTextSize, + this.instructionsSecondRowTextSize, + this.guidanceRecommendedLaneColor, + }); + + int? primaryDayModeBackgroundColor; + + int? secondaryDayModeBackgroundColor; + + int? primaryNightModeBackgroundColor; + + int? secondaryNightModeBackgroundColor; + + int? largeManeuverIconColor; + + int? smallManeuverIconColor; + + int? nextStepTextColor; + + double? nextStepTextSize; + + int? distanceValueTextColor; + + int? distanceUnitsTextColor; + + double? distanceValueTextSize; + + double? distanceUnitsTextSize; + + int? instructionsTextColor; + + double? instructionsFirstRowTextSize; + + double? instructionsSecondRowTextSize; + + int? guidanceRecommendedLaneColor; + + List _toList() { + return [ + primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor, + largeManeuverIconColor, + smallManeuverIconColor, + nextStepTextColor, + nextStepTextSize, + distanceValueTextColor, + distanceUnitsTextColor, + distanceValueTextSize, + distanceUnitsTextSize, + instructionsTextColor, + instructionsFirstRowTextSize, + instructionsSecondRowTextSize, + guidanceRecommendedLaneColor, + ]; + } + + Object encode() { + return _toList(); + } + + static NavigationHeaderStylingOptionsDto decode(Object result) { + result as List; + return NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor: result[0] as int?, + secondaryDayModeBackgroundColor: result[1] as int?, + primaryNightModeBackgroundColor: result[2] as int?, + secondaryNightModeBackgroundColor: result[3] as int?, + largeManeuverIconColor: result[4] as int?, + smallManeuverIconColor: result[5] as int?, + nextStepTextColor: result[6] as int?, + nextStepTextSize: result[7] as double?, + distanceValueTextColor: result[8] as int?, + distanceUnitsTextColor: result[9] as int?, + distanceValueTextSize: result[10] as double?, + distanceUnitsTextSize: result[11] as double?, + instructionsTextColor: result[12] as int?, + instructionsFirstRowTextSize: result[13] as double?, + instructionsSecondRowTextSize: result[14] as double?, + guidanceRecommendedLaneColor: result[15] as int?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! NavigationHeaderStylingOptionsDto || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + class RouteTokenOptionsDto { RouteTokenOptionsDto({required this.routeToken, this.travelMode}); @@ -3269,78 +3393,81 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is MapPaddingDto) { buffer.putUint8(178); writeValue(buffer, value.encode()); - } else if (value is RouteTokenOptionsDto) { + } else if (value is NavigationHeaderStylingOptionsDto) { buffer.putUint8(179); writeValue(buffer, value.encode()); - } else if (value is DestinationsDto) { + } else if (value is RouteTokenOptionsDto) { buffer.putUint8(180); writeValue(buffer, value.encode()); - } else if (value is RoutingOptionsDto) { + } else if (value is DestinationsDto) { buffer.putUint8(181); writeValue(buffer, value.encode()); - } else if (value is NavigationDisplayOptionsDto) { + } else if (value is RoutingOptionsDto) { buffer.putUint8(182); writeValue(buffer, value.encode()); - } else if (value is NavigationWaypointDto) { + } else if (value is NavigationDisplayOptionsDto) { buffer.putUint8(183); writeValue(buffer, value.encode()); - } else if (value is ContinueToNextDestinationResponseDto) { + } else if (value is NavigationWaypointDto) { buffer.putUint8(184); writeValue(buffer, value.encode()); - } else if (value is NavigationTimeAndDistanceDto) { + } else if (value is ContinueToNextDestinationResponseDto) { buffer.putUint8(185); writeValue(buffer, value.encode()); - } else if (value is NavigationAudioGuidanceSettingsDto) { + } else if (value is NavigationTimeAndDistanceDto) { buffer.putUint8(186); writeValue(buffer, value.encode()); - } else if (value is SimulationOptionsDto) { + } else if (value is NavigationAudioGuidanceSettingsDto) { buffer.putUint8(187); writeValue(buffer, value.encode()); - } else if (value is LatLngDto) { + } else if (value is SimulationOptionsDto) { buffer.putUint8(188); writeValue(buffer, value.encode()); - } else if (value is LatLngBoundsDto) { + } else if (value is LatLngDto) { buffer.putUint8(189); writeValue(buffer, value.encode()); - } else if (value is SpeedingUpdatedEventDto) { + } else if (value is LatLngBoundsDto) { buffer.putUint8(190); writeValue(buffer, value.encode()); - } else if (value is GpsAvailabilityChangeEventDto) { + } else if (value is SpeedingUpdatedEventDto) { buffer.putUint8(191); writeValue(buffer, value.encode()); - } else if (value is SpeedAlertOptionsThresholdPercentageDto) { + } else if (value is GpsAvailabilityChangeEventDto) { buffer.putUint8(192); writeValue(buffer, value.encode()); - } else if (value is SpeedAlertOptionsDto) { + } else if (value is SpeedAlertOptionsThresholdPercentageDto) { buffer.putUint8(193); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentTrafficDataRoadStretchRenderingDataDto) { + } else if (value is SpeedAlertOptionsDto) { buffer.putUint8(194); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentTrafficDataDto) { + } else if (value is RouteSegmentTrafficDataRoadStretchRenderingDataDto) { buffer.putUint8(195); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentDto) { + } else if (value is RouteSegmentTrafficDataDto) { buffer.putUint8(196); writeValue(buffer, value.encode()); - } else if (value is LaneDirectionDto) { + } else if (value is RouteSegmentDto) { buffer.putUint8(197); writeValue(buffer, value.encode()); - } else if (value is LaneDto) { + } else if (value is LaneDirectionDto) { buffer.putUint8(198); writeValue(buffer, value.encode()); - } else if (value is StepInfoDto) { + } else if (value is LaneDto) { buffer.putUint8(199); writeValue(buffer, value.encode()); - } else if (value is NavInfoDto) { + } else if (value is StepInfoDto) { buffer.putUint8(200); writeValue(buffer, value.encode()); - } else if (value is TermsAndConditionsUIParamsDto) { + } else if (value is NavInfoDto) { buffer.putUint8(201); writeValue(buffer, value.encode()); - } else if (value is StepImageGenerationOptionsDto) { + } else if (value is TermsAndConditionsUIParamsDto) { buffer.putUint8(202); writeValue(buffer, value.encode()); + } else if (value is StepImageGenerationOptionsDto) { + buffer.putUint8(203); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -3483,56 +3610,58 @@ class _PigeonCodec extends StandardMessageCodec { case 178: return MapPaddingDto.decode(readValue(buffer)!); case 179: - return RouteTokenOptionsDto.decode(readValue(buffer)!); + return NavigationHeaderStylingOptionsDto.decode(readValue(buffer)!); case 180: - return DestinationsDto.decode(readValue(buffer)!); + return RouteTokenOptionsDto.decode(readValue(buffer)!); case 181: - return RoutingOptionsDto.decode(readValue(buffer)!); + return DestinationsDto.decode(readValue(buffer)!); case 182: - return NavigationDisplayOptionsDto.decode(readValue(buffer)!); + return RoutingOptionsDto.decode(readValue(buffer)!); case 183: - return NavigationWaypointDto.decode(readValue(buffer)!); + return NavigationDisplayOptionsDto.decode(readValue(buffer)!); case 184: - return ContinueToNextDestinationResponseDto.decode(readValue(buffer)!); + return NavigationWaypointDto.decode(readValue(buffer)!); case 185: - return NavigationTimeAndDistanceDto.decode(readValue(buffer)!); + return ContinueToNextDestinationResponseDto.decode(readValue(buffer)!); case 186: - return NavigationAudioGuidanceSettingsDto.decode(readValue(buffer)!); + return NavigationTimeAndDistanceDto.decode(readValue(buffer)!); case 187: - return SimulationOptionsDto.decode(readValue(buffer)!); + return NavigationAudioGuidanceSettingsDto.decode(readValue(buffer)!); case 188: - return LatLngDto.decode(readValue(buffer)!); + return SimulationOptionsDto.decode(readValue(buffer)!); case 189: - return LatLngBoundsDto.decode(readValue(buffer)!); + return LatLngDto.decode(readValue(buffer)!); case 190: - return SpeedingUpdatedEventDto.decode(readValue(buffer)!); + return LatLngBoundsDto.decode(readValue(buffer)!); case 191: - return GpsAvailabilityChangeEventDto.decode(readValue(buffer)!); + return SpeedingUpdatedEventDto.decode(readValue(buffer)!); case 192: + return GpsAvailabilityChangeEventDto.decode(readValue(buffer)!); + case 193: return SpeedAlertOptionsThresholdPercentageDto.decode( readValue(buffer)!, ); - case 193: - return SpeedAlertOptionsDto.decode(readValue(buffer)!); case 194: + return SpeedAlertOptionsDto.decode(readValue(buffer)!); + case 195: return RouteSegmentTrafficDataRoadStretchRenderingDataDto.decode( readValue(buffer)!, ); - case 195: - return RouteSegmentTrafficDataDto.decode(readValue(buffer)!); case 196: - return RouteSegmentDto.decode(readValue(buffer)!); + return RouteSegmentTrafficDataDto.decode(readValue(buffer)!); case 197: - return LaneDirectionDto.decode(readValue(buffer)!); + return RouteSegmentDto.decode(readValue(buffer)!); case 198: - return LaneDto.decode(readValue(buffer)!); + return LaneDirectionDto.decode(readValue(buffer)!); case 199: - return StepInfoDto.decode(readValue(buffer)!); + return LaneDto.decode(readValue(buffer)!); case 200: - return NavInfoDto.decode(readValue(buffer)!); + return StepInfoDto.decode(readValue(buffer)!); case 201: - return TermsAndConditionsUIParamsDto.decode(readValue(buffer)!); + return NavInfoDto.decode(readValue(buffer)!); case 202: + return TermsAndConditionsUIParamsDto.decode(readValue(buffer)!); + case 203: return StepImageGenerationOptionsDto.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -3928,6 +4057,70 @@ class MapViewApi { } } + Future getNavigationHeaderStylingOptions( + int viewId, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [viewId], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as NavigationHeaderStylingOptionsDto?)!; + } + } + + Future setNavigationHeaderStylingOptions( + int viewId, + NavigationHeaderStylingOptionsDto stylingOptions, + ) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [viewId, stylingOptions], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + Future isNavigationFooterEnabled(int viewId) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.google_navigation_flutter.MapViewApi.isNavigationFooterEnabled$pigeonVar_messageChannelSuffix'; diff --git a/lib/src/types/navigation_header_styling_options.dart b/lib/src/types/navigation_header_styling_options.dart new file mode 100644 index 00000000..9f3fdc06 --- /dev/null +++ b/lib/src/types/navigation_header_styling_options.dart @@ -0,0 +1,253 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:flutter/widgets.dart'; + +import '../method_channel/messages.g.dart'; + +/// Styling options for the native navigation header. +/// +/// Text size properties are currently supported on Android only. On iOS they +/// are ignored. +/// {@category Navigation View} +class NavigationHeaderStylingOptions { + /// Creates navigation header styling options. + const NavigationHeaderStylingOptions({ + this.primaryDayModeBackgroundColor, + this.secondaryDayModeBackgroundColor, + this.primaryNightModeBackgroundColor, + this.secondaryNightModeBackgroundColor, + this.largeManeuverIconColor, + this.smallManeuverIconColor, + this.nextStepTextColor, + this.nextStepTextSize, + this.distanceValueTextColor, + this.distanceUnitsTextColor, + this.distanceValueTextSize, + this.distanceUnitsTextSize, + this.instructionsTextColor, + this.instructionsFirstRowTextSize, + this.instructionsSecondRowTextSize, + this.guidanceRecommendedLaneColor, + }); + + /// Background color of the primary header area in day mode. + final Color? primaryDayModeBackgroundColor; + + /// Background color of the secondary header area in day mode. + final Color? secondaryDayModeBackgroundColor; + + /// Background color of the primary header area in night mode. + final Color? primaryNightModeBackgroundColor; + + /// Background color of the secondary header area in night mode. + final Color? secondaryNightModeBackgroundColor; + + /// Color of the large maneuver icon in the header. + final Color? largeManeuverIconColor; + + /// Color of the small maneuver icon in the header. + final Color? smallManeuverIconColor; + + /// Color of the next-step text in the header. + final Color? nextStepTextColor; + + /// Size of the next-step text in logical pixels. + /// + /// Android only. Ignored on iOS. + final double? nextStepTextSize; + + /// Color of the distance value text in the header. + final Color? distanceValueTextColor; + + /// Color of the distance units text in the header. + final Color? distanceUnitsTextColor; + + /// Size of the distance value text in logical pixels. + /// + /// Android only. Ignored on iOS. + final double? distanceValueTextSize; + + /// Size of the distance units text in logical pixels. + /// + /// Android only. Ignored on iOS. + final double? distanceUnitsTextSize; + + /// Color of the instructions text in the header. + final Color? instructionsTextColor; + + /// Size of the first row of the instructions text in logical pixels. + /// + /// Android only. Ignored on iOS. + final double? instructionsFirstRowTextSize; + + /// Size of the second row of the instructions text in logical pixels. + /// + /// Android only. Ignored on iOS. + final double? instructionsSecondRowTextSize; + + /// Color of the recommended lane highlight in the header. + final Color? guidanceRecommendedLaneColor; + + /// Returns a copy with selected fields replaced. + NavigationHeaderStylingOptions copyWith({ + Color? primaryDayModeBackgroundColor, + Color? secondaryDayModeBackgroundColor, + Color? primaryNightModeBackgroundColor, + Color? secondaryNightModeBackgroundColor, + Color? largeManeuverIconColor, + Color? smallManeuverIconColor, + Color? nextStepTextColor, + double? nextStepTextSize, + Color? distanceValueTextColor, + Color? distanceUnitsTextColor, + double? distanceValueTextSize, + double? distanceUnitsTextSize, + Color? instructionsTextColor, + double? instructionsFirstRowTextSize, + double? instructionsSecondRowTextSize, + Color? guidanceRecommendedLaneColor, + }) { + return NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: + primaryDayModeBackgroundColor ?? this.primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor: + secondaryDayModeBackgroundColor ?? + this.secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor: + primaryNightModeBackgroundColor ?? + this.primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor: + secondaryNightModeBackgroundColor ?? + this.secondaryNightModeBackgroundColor, + largeManeuverIconColor: + largeManeuverIconColor ?? this.largeManeuverIconColor, + smallManeuverIconColor: + smallManeuverIconColor ?? this.smallManeuverIconColor, + nextStepTextColor: nextStepTextColor ?? this.nextStepTextColor, + nextStepTextSize: nextStepTextSize ?? this.nextStepTextSize, + distanceValueTextColor: + distanceValueTextColor ?? this.distanceValueTextColor, + distanceUnitsTextColor: + distanceUnitsTextColor ?? this.distanceUnitsTextColor, + distanceValueTextSize: + distanceValueTextSize ?? this.distanceValueTextSize, + distanceUnitsTextSize: + distanceUnitsTextSize ?? this.distanceUnitsTextSize, + instructionsTextColor: + instructionsTextColor ?? this.instructionsTextColor, + instructionsFirstRowTextSize: + instructionsFirstRowTextSize ?? this.instructionsFirstRowTextSize, + instructionsSecondRowTextSize: + instructionsSecondRowTextSize ?? this.instructionsSecondRowTextSize, + guidanceRecommendedLaneColor: + guidanceRecommendedLaneColor ?? this.guidanceRecommendedLaneColor, + ); + } + + /// Converts this object to a pigeon DTO. + NavigationHeaderStylingOptionsDto toDto() { + return NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor: primaryDayModeBackgroundColor?.toARGB32(), + secondaryDayModeBackgroundColor: secondaryDayModeBackgroundColor + ?.toARGB32(), + primaryNightModeBackgroundColor: primaryNightModeBackgroundColor + ?.toARGB32(), + secondaryNightModeBackgroundColor: secondaryNightModeBackgroundColor + ?.toARGB32(), + largeManeuverIconColor: largeManeuverIconColor?.toARGB32(), + smallManeuverIconColor: smallManeuverIconColor?.toARGB32(), + nextStepTextColor: nextStepTextColor?.toARGB32(), + nextStepTextSize: nextStepTextSize, + distanceValueTextColor: distanceValueTextColor?.toARGB32(), + distanceUnitsTextColor: distanceUnitsTextColor?.toARGB32(), + distanceValueTextSize: distanceValueTextSize, + distanceUnitsTextSize: distanceUnitsTextSize, + instructionsTextColor: instructionsTextColor?.toARGB32(), + instructionsFirstRowTextSize: instructionsFirstRowTextSize, + instructionsSecondRowTextSize: instructionsSecondRowTextSize, + guidanceRecommendedLaneColor: guidanceRecommendedLaneColor?.toARGB32(), + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + return other is NavigationHeaderStylingOptions && + other.primaryDayModeBackgroundColor == primaryDayModeBackgroundColor && + other.secondaryDayModeBackgroundColor == + secondaryDayModeBackgroundColor && + other.primaryNightModeBackgroundColor == + primaryNightModeBackgroundColor && + other.secondaryNightModeBackgroundColor == + secondaryNightModeBackgroundColor && + other.largeManeuverIconColor == largeManeuverIconColor && + other.smallManeuverIconColor == smallManeuverIconColor && + other.nextStepTextColor == nextStepTextColor && + other.nextStepTextSize == nextStepTextSize && + other.distanceValueTextColor == distanceValueTextColor && + other.distanceUnitsTextColor == distanceUnitsTextColor && + other.distanceValueTextSize == distanceValueTextSize && + other.distanceUnitsTextSize == distanceUnitsTextSize && + other.instructionsTextColor == instructionsTextColor && + other.instructionsFirstRowTextSize == instructionsFirstRowTextSize && + other.instructionsSecondRowTextSize == instructionsSecondRowTextSize && + other.guidanceRecommendedLaneColor == guidanceRecommendedLaneColor; + } + + @override + int get hashCode => Object.hash( + primaryDayModeBackgroundColor, + secondaryDayModeBackgroundColor, + primaryNightModeBackgroundColor, + secondaryNightModeBackgroundColor, + largeManeuverIconColor, + smallManeuverIconColor, + nextStepTextColor, + nextStepTextSize, + distanceValueTextColor, + distanceUnitsTextColor, + distanceValueTextSize, + distanceUnitsTextSize, + instructionsTextColor, + instructionsFirstRowTextSize, + instructionsSecondRowTextSize, + guidanceRecommendedLaneColor, + ); + + @override + String toString() { + return 'NavigationHeaderStylingOptions(' + 'primaryDayModeBackgroundColor: $primaryDayModeBackgroundColor, ' + 'secondaryDayModeBackgroundColor: $secondaryDayModeBackgroundColor, ' + 'primaryNightModeBackgroundColor: $primaryNightModeBackgroundColor, ' + 'secondaryNightModeBackgroundColor: $secondaryNightModeBackgroundColor, ' + 'largeManeuverIconColor: $largeManeuverIconColor, ' + 'smallManeuverIconColor: $smallManeuverIconColor, ' + 'nextStepTextColor: $nextStepTextColor, ' + 'nextStepTextSize: $nextStepTextSize, ' + 'distanceValueTextColor: $distanceValueTextColor, ' + 'distanceUnitsTextColor: $distanceUnitsTextColor, ' + 'distanceValueTextSize: $distanceValueTextSize, ' + 'distanceUnitsTextSize: $distanceUnitsTextSize, ' + 'instructionsTextColor: $instructionsTextColor, ' + 'instructionsFirstRowTextSize: $instructionsFirstRowTextSize, ' + 'instructionsSecondRowTextSize: $instructionsSecondRowTextSize, ' + 'guidanceRecommendedLaneColor: $guidanceRecommendedLaneColor' + ')'; + } +} diff --git a/lib/src/types/types.dart b/lib/src/types/types.dart index d483b364..3f2af579 100644 --- a/lib/src/types/types.dart +++ b/lib/src/types/types.dart @@ -20,6 +20,7 @@ export 'lat_lng_bounds.dart'; export 'markers.dart'; export 'navigation.dart'; export 'navigation_destinations.dart'; +export 'navigation_header_styling_options.dart'; export 'navigation_initialization_params.dart'; export 'navigation_view_types.dart'; export 'navinfo.dart'; diff --git a/pigeons/messages.dart b/pigeons/messages.dart index b6193cda..ebb73411 100644 --- a/pigeons/messages.dart +++ b/pigeons/messages.dart @@ -525,6 +525,51 @@ class MapPaddingDto { final int right; } +/// Navigation header styling options. +/// +/// All color values are 32-bit ARGB integers (format: 0xAARRGGBB). +/// All text size values are logical pixels. +/// Any null value resets that specific field to the native SDK default. +/// +/// Text size fields are currently Android only and are ignored on iOS. +class NavigationHeaderStylingOptionsDto { + NavigationHeaderStylingOptionsDto({ + this.primaryDayModeBackgroundColor, + this.secondaryDayModeBackgroundColor, + this.primaryNightModeBackgroundColor, + this.secondaryNightModeBackgroundColor, + this.largeManeuverIconColor, + this.smallManeuverIconColor, + this.nextStepTextColor, + this.nextStepTextSize, + this.distanceValueTextColor, + this.distanceUnitsTextColor, + this.distanceValueTextSize, + this.distanceUnitsTextSize, + this.instructionsTextColor, + this.instructionsFirstRowTextSize, + this.instructionsSecondRowTextSize, + this.guidanceRecommendedLaneColor, + }); + + final int? primaryDayModeBackgroundColor; + final int? secondaryDayModeBackgroundColor; + final int? primaryNightModeBackgroundColor; + final int? secondaryNightModeBackgroundColor; + final int? largeManeuverIconColor; + final int? smallManeuverIconColor; + final int? nextStepTextColor; + final double? nextStepTextSize; + final int? distanceValueTextColor; + final int? distanceUnitsTextColor; + final double? distanceValueTextSize; + final double? distanceUnitsTextSize; + final int? instructionsTextColor; + final double? instructionsFirstRowTextSize; + final double? instructionsSecondRowTextSize; + final int? guidanceRecommendedLaneColor; +} + @HostApi(dartHostTestHandler: 'TestMapViewApi') abstract class MapViewApi { @async @@ -544,6 +589,14 @@ abstract class MapViewApi { bool isNavigationHeaderEnabled(int viewId); void setNavigationHeaderEnabled(int viewId, bool enabled); + NavigationHeaderStylingOptionsDto getNavigationHeaderStylingOptions( + int viewId, + ); + void setNavigationHeaderStylingOptions( + int viewId, + NavigationHeaderStylingOptionsDto stylingOptions, + ); + bool isNavigationFooterEnabled(int viewId); void setNavigationFooterEnabled(int viewId, bool enabled); diff --git a/test/google_navigation_flutter_test.dart b/test/google_navigation_flutter_test.dart index 41d2095c..1e8ad6f8 100644 --- a/test/google_navigation_flutter_test.dart +++ b/test/google_navigation_flutter_test.dart @@ -62,6 +62,16 @@ void main() { TestImageRegistryApi.setUp(imageRegistryMockApi); }); + T anyAs() { + // ignore: cast_from_null_always_fails + return any as T; + } + + T captureAnyAs() { + // ignore: cast_from_null_always_fails + return captureAny as T; + } + void verifyEnabled(VerificationResult result, bool enabled) { final bool enabledOut = result.captured[1] as bool; expect(enabledOut, enabled); @@ -689,7 +699,31 @@ void main() { isUnderground: false, ), ); - when(viewMockApi.isNavigationHeaderEnabled(any)).thenReturn(true); + when( + viewMockApi.isNavigationHeaderEnabled(anyAs()), + ).thenReturn(true); + when( + viewMockApi.getNavigationHeaderStylingOptions(anyAs()), + ).thenReturn( + NavigationHeaderStylingOptionsDto( + primaryDayModeBackgroundColor: Colors.blue.toARGB32(), + secondaryDayModeBackgroundColor: Colors.red.toARGB32(), + primaryNightModeBackgroundColor: Colors.black.toARGB32(), + secondaryNightModeBackgroundColor: Colors.grey.toARGB32(), + largeManeuverIconColor: Colors.orange.toARGB32(), + smallManeuverIconColor: Colors.pink.toARGB32(), + nextStepTextColor: Colors.yellow.toARGB32(), + nextStepTextSize: 18, + distanceValueTextColor: Colors.green.toARGB32(), + distanceUnitsTextColor: Colors.lime.toARGB32(), + distanceValueTextSize: 24, + distanceUnitsTextSize: 14, + instructionsTextColor: Colors.cyan.toARGB32(), + instructionsFirstRowTextSize: 30, + instructionsSecondRowTextSize: 20, + guidanceRecommendedLaneColor: Colors.teal.toARGB32(), + ), + ); when(viewMockApi.isNavigationFooterEnabled(any)).thenReturn(true); when(viewMockApi.isSpeedLimitIconEnabled(any)).thenReturn(true); when(viewMockApi.isSpeedometerEnabled(any)).thenReturn(true); @@ -723,6 +757,27 @@ void main() { expect(focusedIndoorBuilding.activeLevelIndex, 1); await controller.activateIndoorLevel(focusedIndoorBuilding.levels[0]); expect(await controller.isNavigationHeaderEnabled(), true); + expect( + await controller.getNavigationHeaderStylingOptions(), + const NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: Colors.blue, + secondaryDayModeBackgroundColor: Colors.red, + primaryNightModeBackgroundColor: Colors.black, + secondaryNightModeBackgroundColor: Colors.grey, + largeManeuverIconColor: Colors.orange, + smallManeuverIconColor: Colors.pink, + nextStepTextColor: Colors.yellow, + nextStepTextSize: 18, + distanceValueTextColor: Colors.green, + distanceUnitsTextColor: Colors.lime, + distanceValueTextSize: 24, + distanceUnitsTextSize: 14, + instructionsTextColor: Colors.cyan, + instructionsFirstRowTextSize: 30, + instructionsSecondRowTextSize: 20, + guidanceRecommendedLaneColor: Colors.teal, + ), + ); expect(await controller.isNavigationFooterEnabled(), true); expect(await controller.isSpeedLimitIconEnabled(), true); expect(await controller.isSpeedometerEnabled(), true); @@ -749,7 +804,10 @@ void main() { verify(viewMockApi.isIndoorLevelPickerEnabled(captureAny)); verify(viewMockApi.getFocusedIndoorBuilding(captureAny)); verify(viewMockApi.activateIndoorLevel(captureAny, captureAny)); - verify(viewMockApi.isNavigationHeaderEnabled(captureAny)); + verify(viewMockApi.isNavigationHeaderEnabled(captureAnyAs())); + verify( + viewMockApi.getNavigationHeaderStylingOptions(captureAnyAs()), + ); verify(viewMockApi.isNavigationFooterEnabled(captureAny)); verify(viewMockApi.isSpeedLimitIconEnabled(captureAny)); verify(viewMockApi.isSpeedometerEnabled(captureAny)); @@ -776,6 +834,26 @@ void main() { await controller.setIndoorEnabled(true); await controller.settings.setIndoorLevelPickerEnabled(true); await controller.setNavigationHeaderEnabled(true); + await controller.setNavigationHeaderStylingOptions( + const NavigationHeaderStylingOptions( + primaryDayModeBackgroundColor: Colors.green, + secondaryDayModeBackgroundColor: Colors.orange, + primaryNightModeBackgroundColor: Colors.white, + secondaryNightModeBackgroundColor: Colors.purple, + largeManeuverIconColor: Colors.amber, + smallManeuverIconColor: Colors.deepOrange, + nextStepTextColor: Colors.brown, + nextStepTextSize: 19, + distanceValueTextColor: Colors.indigo, + distanceUnitsTextColor: Colors.deepPurple, + distanceValueTextSize: 25, + distanceUnitsTextSize: 15, + instructionsTextColor: Colors.lightBlue, + instructionsFirstRowTextSize: 31, + instructionsSecondRowTextSize: 21, + guidanceRecommendedLaneColor: Colors.lightGreen, + ), + ); await controller.setNavigationFooterEnabled(true); await controller.setSpeedLimitIconEnabled(true); await controller.setSpeedometerEnabled(true); @@ -870,6 +948,61 @@ void main() { ), true, ); + final VerificationResult headerStylingResult = verify( + viewMockApi.setNavigationHeaderStylingOptions( + captureAnyAs(), + captureAnyAs(), + ), + ); + final NavigationHeaderStylingOptionsDto headerStylingOut = + headerStylingResult.captured[1] + as NavigationHeaderStylingOptionsDto; + expect( + headerStylingOut.primaryDayModeBackgroundColor, + Colors.green.toARGB32(), + ); + expect( + headerStylingOut.secondaryDayModeBackgroundColor, + Colors.orange.toARGB32(), + ); + expect( + headerStylingOut.primaryNightModeBackgroundColor, + Colors.white.toARGB32(), + ); + expect( + headerStylingOut.secondaryNightModeBackgroundColor, + Colors.purple.toARGB32(), + ); + expect( + headerStylingOut.largeManeuverIconColor, + Colors.amber.toARGB32(), + ); + expect( + headerStylingOut.smallManeuverIconColor, + Colors.deepOrange.toARGB32(), + ); + expect(headerStylingOut.nextStepTextColor, Colors.brown.toARGB32()); + expect(headerStylingOut.nextStepTextSize, 19); + expect( + headerStylingOut.distanceValueTextColor, + Colors.indigo.toARGB32(), + ); + expect( + headerStylingOut.distanceUnitsTextColor, + Colors.deepPurple.toARGB32(), + ); + expect(headerStylingOut.distanceValueTextSize, 25); + expect(headerStylingOut.distanceUnitsTextSize, 15); + expect( + headerStylingOut.instructionsTextColor, + Colors.lightBlue.toARGB32(), + ); + expect(headerStylingOut.instructionsFirstRowTextSize, 31); + expect(headerStylingOut.instructionsSecondRowTextSize, 21); + expect( + headerStylingOut.guidanceRecommendedLaneColor, + Colors.lightGreen.toARGB32(), + ); verifyEnabled( verify( viewMockApi.setNavigationFooterEnabled(captureAny, captureAny), diff --git a/test/messages_test.g.dart b/test/messages_test.g.dart index e5f04029..7a905b66 100644 --- a/test/messages_test.g.dart +++ b/test/messages_test.g.dart @@ -182,78 +182,81 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is MapPaddingDto) { buffer.putUint8(178); writeValue(buffer, value.encode()); - } else if (value is RouteTokenOptionsDto) { + } else if (value is NavigationHeaderStylingOptionsDto) { buffer.putUint8(179); writeValue(buffer, value.encode()); - } else if (value is DestinationsDto) { + } else if (value is RouteTokenOptionsDto) { buffer.putUint8(180); writeValue(buffer, value.encode()); - } else if (value is RoutingOptionsDto) { + } else if (value is DestinationsDto) { buffer.putUint8(181); writeValue(buffer, value.encode()); - } else if (value is NavigationDisplayOptionsDto) { + } else if (value is RoutingOptionsDto) { buffer.putUint8(182); writeValue(buffer, value.encode()); - } else if (value is NavigationWaypointDto) { + } else if (value is NavigationDisplayOptionsDto) { buffer.putUint8(183); writeValue(buffer, value.encode()); - } else if (value is ContinueToNextDestinationResponseDto) { + } else if (value is NavigationWaypointDto) { buffer.putUint8(184); writeValue(buffer, value.encode()); - } else if (value is NavigationTimeAndDistanceDto) { + } else if (value is ContinueToNextDestinationResponseDto) { buffer.putUint8(185); writeValue(buffer, value.encode()); - } else if (value is NavigationAudioGuidanceSettingsDto) { + } else if (value is NavigationTimeAndDistanceDto) { buffer.putUint8(186); writeValue(buffer, value.encode()); - } else if (value is SimulationOptionsDto) { + } else if (value is NavigationAudioGuidanceSettingsDto) { buffer.putUint8(187); writeValue(buffer, value.encode()); - } else if (value is LatLngDto) { + } else if (value is SimulationOptionsDto) { buffer.putUint8(188); writeValue(buffer, value.encode()); - } else if (value is LatLngBoundsDto) { + } else if (value is LatLngDto) { buffer.putUint8(189); writeValue(buffer, value.encode()); - } else if (value is SpeedingUpdatedEventDto) { + } else if (value is LatLngBoundsDto) { buffer.putUint8(190); writeValue(buffer, value.encode()); - } else if (value is GpsAvailabilityChangeEventDto) { + } else if (value is SpeedingUpdatedEventDto) { buffer.putUint8(191); writeValue(buffer, value.encode()); - } else if (value is SpeedAlertOptionsThresholdPercentageDto) { + } else if (value is GpsAvailabilityChangeEventDto) { buffer.putUint8(192); writeValue(buffer, value.encode()); - } else if (value is SpeedAlertOptionsDto) { + } else if (value is SpeedAlertOptionsThresholdPercentageDto) { buffer.putUint8(193); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentTrafficDataRoadStretchRenderingDataDto) { + } else if (value is SpeedAlertOptionsDto) { buffer.putUint8(194); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentTrafficDataDto) { + } else if (value is RouteSegmentTrafficDataRoadStretchRenderingDataDto) { buffer.putUint8(195); writeValue(buffer, value.encode()); - } else if (value is RouteSegmentDto) { + } else if (value is RouteSegmentTrafficDataDto) { buffer.putUint8(196); writeValue(buffer, value.encode()); - } else if (value is LaneDirectionDto) { + } else if (value is RouteSegmentDto) { buffer.putUint8(197); writeValue(buffer, value.encode()); - } else if (value is LaneDto) { + } else if (value is LaneDirectionDto) { buffer.putUint8(198); writeValue(buffer, value.encode()); - } else if (value is StepInfoDto) { + } else if (value is LaneDto) { buffer.putUint8(199); writeValue(buffer, value.encode()); - } else if (value is NavInfoDto) { + } else if (value is StepInfoDto) { buffer.putUint8(200); writeValue(buffer, value.encode()); - } else if (value is TermsAndConditionsUIParamsDto) { + } else if (value is NavInfoDto) { buffer.putUint8(201); writeValue(buffer, value.encode()); - } else if (value is StepImageGenerationOptionsDto) { + } else if (value is TermsAndConditionsUIParamsDto) { buffer.putUint8(202); writeValue(buffer, value.encode()); + } else if (value is StepImageGenerationOptionsDto) { + buffer.putUint8(203); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -396,56 +399,58 @@ class _PigeonCodec extends StandardMessageCodec { case 178: return MapPaddingDto.decode(readValue(buffer)!); case 179: - return RouteTokenOptionsDto.decode(readValue(buffer)!); + return NavigationHeaderStylingOptionsDto.decode(readValue(buffer)!); case 180: - return DestinationsDto.decode(readValue(buffer)!); + return RouteTokenOptionsDto.decode(readValue(buffer)!); case 181: - return RoutingOptionsDto.decode(readValue(buffer)!); + return DestinationsDto.decode(readValue(buffer)!); case 182: - return NavigationDisplayOptionsDto.decode(readValue(buffer)!); + return RoutingOptionsDto.decode(readValue(buffer)!); case 183: - return NavigationWaypointDto.decode(readValue(buffer)!); + return NavigationDisplayOptionsDto.decode(readValue(buffer)!); case 184: - return ContinueToNextDestinationResponseDto.decode(readValue(buffer)!); + return NavigationWaypointDto.decode(readValue(buffer)!); case 185: - return NavigationTimeAndDistanceDto.decode(readValue(buffer)!); + return ContinueToNextDestinationResponseDto.decode(readValue(buffer)!); case 186: - return NavigationAudioGuidanceSettingsDto.decode(readValue(buffer)!); + return NavigationTimeAndDistanceDto.decode(readValue(buffer)!); case 187: - return SimulationOptionsDto.decode(readValue(buffer)!); + return NavigationAudioGuidanceSettingsDto.decode(readValue(buffer)!); case 188: - return LatLngDto.decode(readValue(buffer)!); + return SimulationOptionsDto.decode(readValue(buffer)!); case 189: - return LatLngBoundsDto.decode(readValue(buffer)!); + return LatLngDto.decode(readValue(buffer)!); case 190: - return SpeedingUpdatedEventDto.decode(readValue(buffer)!); + return LatLngBoundsDto.decode(readValue(buffer)!); case 191: - return GpsAvailabilityChangeEventDto.decode(readValue(buffer)!); + return SpeedingUpdatedEventDto.decode(readValue(buffer)!); case 192: + return GpsAvailabilityChangeEventDto.decode(readValue(buffer)!); + case 193: return SpeedAlertOptionsThresholdPercentageDto.decode( readValue(buffer)!, ); - case 193: - return SpeedAlertOptionsDto.decode(readValue(buffer)!); case 194: + return SpeedAlertOptionsDto.decode(readValue(buffer)!); + case 195: return RouteSegmentTrafficDataRoadStretchRenderingDataDto.decode( readValue(buffer)!, ); - case 195: - return RouteSegmentTrafficDataDto.decode(readValue(buffer)!); case 196: - return RouteSegmentDto.decode(readValue(buffer)!); + return RouteSegmentTrafficDataDto.decode(readValue(buffer)!); case 197: - return LaneDirectionDto.decode(readValue(buffer)!); + return RouteSegmentDto.decode(readValue(buffer)!); case 198: - return LaneDto.decode(readValue(buffer)!); + return LaneDirectionDto.decode(readValue(buffer)!); case 199: - return StepInfoDto.decode(readValue(buffer)!); + return LaneDto.decode(readValue(buffer)!); case 200: - return NavInfoDto.decode(readValue(buffer)!); + return StepInfoDto.decode(readValue(buffer)!); case 201: - return TermsAndConditionsUIParamsDto.decode(readValue(buffer)!); + return NavInfoDto.decode(readValue(buffer)!); case 202: + return TermsAndConditionsUIParamsDto.decode(readValue(buffer)!); + case 203: return StepImageGenerationOptionsDto.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -480,6 +485,15 @@ abstract class TestMapViewApi { void setNavigationHeaderEnabled(int viewId, bool enabled); + NavigationHeaderStylingOptionsDto getNavigationHeaderStylingOptions( + int viewId, + ); + + void setNavigationHeaderStylingOptions( + int viewId, + NavigationHeaderStylingOptionsDto stylingOptions, + ); + bool isNavigationFooterEnabled(int viewId); void setNavigationFooterEnabled(int viewId, bool enabled); @@ -1192,6 +1206,94 @@ abstract class TestMapViewApi { }); } } + { + final BasicMessageChannel + pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, ( + Object? message, + ) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions was null.', + ); + final List args = (message as List?)!; + final int? arg_viewId = (args[0] as int?); + assert( + arg_viewId != null, + 'Argument for dev.flutter.pigeon.google_navigation_flutter.MapViewApi.getNavigationHeaderStylingOptions was null, expected non-null int.', + ); + try { + final NavigationHeaderStylingOptionsDto output = api + .getNavigationHeaderStylingOptions(arg_viewId!); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException( + code: 'error', + message: e.toString(), + ), + ); + } + }); + } + } + { + final BasicMessageChannel + pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler< + Object? + >(pigeonVar_channel, (Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions was null.', + ); + final List args = (message as List?)!; + final int? arg_viewId = (args[0] as int?); + assert( + arg_viewId != null, + 'Argument for dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions was null, expected non-null int.', + ); + final NavigationHeaderStylingOptionsDto? arg_stylingOptions = + (args[1] as NavigationHeaderStylingOptionsDto?); + assert( + arg_stylingOptions != null, + 'Argument for dev.flutter.pigeon.google_navigation_flutter.MapViewApi.setNavigationHeaderStylingOptions was null, expected non-null NavigationHeaderStylingOptionsDto.', + ); + try { + api.setNavigationHeaderStylingOptions( + arg_viewId!, + arg_stylingOptions!, + ); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } { final BasicMessageChannel pigeonVar_channel = BasicMessageChannel(