@javascriptcommon/react-native-carplay 2.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +633 -0
  2. package/ios/RCTConvert+RNCarPlay.h +19 -0
  3. package/ios/RCTConvert+RNCarPlay.m +95 -0
  4. package/ios/RNCPStore.h +22 -0
  5. package/ios/RNCPStore.m +68 -0
  6. package/ios/RNCarPlay.h +32 -0
  7. package/ios/RNCarPlay.m +1755 -0
  8. package/ios/RNCarPlay.xcodeproj/project.pbxproj +300 -0
  9. package/lib/CarPlay.js +146 -0
  10. package/lib/index.js +63 -0
  11. package/lib/interfaces/Action.js +2 -0
  12. package/lib/interfaces/AlertAction.js +2 -0
  13. package/lib/interfaces/BarButton.js +2 -0
  14. package/lib/interfaces/CarColor.js +2 -0
  15. package/lib/interfaces/GridButton.js +2 -0
  16. package/lib/interfaces/Header.js +2 -0
  17. package/lib/interfaces/ListItem.js +2 -0
  18. package/lib/interfaces/ListItemUpdate.js +2 -0
  19. package/lib/interfaces/ListSection.js +2 -0
  20. package/lib/interfaces/Maneuver.js +2 -0
  21. package/lib/interfaces/MapButton.js +2 -0
  22. package/lib/interfaces/NavigationAlert.js +9 -0
  23. package/lib/interfaces/NavigationInfo.js +2 -0
  24. package/lib/interfaces/NavigationStep.js +2 -0
  25. package/lib/interfaces/Pane.js +2 -0
  26. package/lib/interfaces/PauseReason.js +11 -0
  27. package/lib/interfaces/Place.js +2 -0
  28. package/lib/interfaces/TextConfiguration.js +2 -0
  29. package/lib/interfaces/TimeRemainingColor.js +2 -0
  30. package/lib/interfaces/TravelEstimates.js +2 -0
  31. package/lib/interfaces/VoiceControlState.js +2 -0
  32. package/lib/navigation/NavigationSession.js +53 -0
  33. package/lib/navigation/Trip.js +19 -0
  34. package/lib/templates/ActionSheetTemplate.js +15 -0
  35. package/lib/templates/AlertTemplate.js +15 -0
  36. package/lib/templates/ContactTemplate.js +15 -0
  37. package/lib/templates/GridTemplate.js +16 -0
  38. package/lib/templates/InformationTemplate.js +24 -0
  39. package/lib/templates/ListTemplate.js +67 -0
  40. package/lib/templates/MapTemplate.js +115 -0
  41. package/lib/templates/NowPlayingTemplate.js +17 -0
  42. package/lib/templates/PointOfInterestTemplate.js +16 -0
  43. package/lib/templates/SearchTemplate.js +41 -0
  44. package/lib/templates/TabBarTemplate.js +26 -0
  45. package/lib/templates/Template.js +74 -0
  46. package/lib/templates/VoiceControlTemplate.js +19 -0
  47. package/lib/templates/android/AndroidNavigationBaseTemplate.js +29 -0
  48. package/lib/templates/android/MessageTemplate.js +10 -0
  49. package/lib/templates/android/NavigationTemplate.js +16 -0
  50. package/lib/templates/android/PaneTemplate.js +10 -0
  51. package/lib/templates/android/PlaceListMapTemplate.js +18 -0
  52. package/lib/templates/android/PlaceListNavigationTemplate.js +19 -0
  53. package/lib/templates/android/RoutePreviewNavigationTemplate.js +22 -0
  54. package/package.json +71 -0
  55. package/react-native-carplay.podspec +21 -0
  56. package/src/CarPlay.ts +286 -0
  57. package/src/index.ts +50 -0
  58. package/src/interfaces/Action.ts +15 -0
  59. package/src/interfaces/AlertAction.ts +5 -0
  60. package/src/interfaces/BarButton.ts +41 -0
  61. package/src/interfaces/CarColor.ts +1 -0
  62. package/src/interfaces/GridButton.ts +25 -0
  63. package/src/interfaces/Header.ts +16 -0
  64. package/src/interfaces/ListItem.ts +84 -0
  65. package/src/interfaces/ListItemUpdate.ts +14 -0
  66. package/src/interfaces/ListSection.ts +21 -0
  67. package/src/interfaces/Maneuver.ts +30 -0
  68. package/src/interfaces/MapButton.ts +27 -0
  69. package/src/interfaces/NavigationAlert.ts +46 -0
  70. package/src/interfaces/NavigationInfo.ts +19 -0
  71. package/src/interfaces/NavigationStep.ts +17 -0
  72. package/src/interfaces/Pane.ts +29 -0
  73. package/src/interfaces/PauseReason.ts +7 -0
  74. package/src/interfaces/Place.ts +12 -0
  75. package/src/interfaces/TextConfiguration.ts +5 -0
  76. package/src/interfaces/TimeRemainingColor.ts +1 -0
  77. package/src/interfaces/TravelEstimates.ts +39 -0
  78. package/src/interfaces/VoiceControlState.ts +8 -0
  79. package/src/navigation/NavigationSession.ts +57 -0
  80. package/src/navigation/Trip.ts +36 -0
  81. package/src/templates/ActionSheetTemplate.ts +21 -0
  82. package/src/templates/AlertTemplate.ts +20 -0
  83. package/src/templates/ContactTemplate.ts +45 -0
  84. package/src/templates/GridTemplate.ts +45 -0
  85. package/src/templates/InformationTemplate.ts +42 -0
  86. package/src/templates/ListTemplate.ts +167 -0
  87. package/src/templates/MapTemplate.ts +231 -0
  88. package/src/templates/NowPlayingTemplate.ts +31 -0
  89. package/src/templates/PointOfInterestTemplate.ts +40 -0
  90. package/src/templates/SearchTemplate.ts +70 -0
  91. package/src/templates/TabBarTemplate.ts +56 -0
  92. package/src/templates/Template.ts +164 -0
  93. package/src/templates/VoiceControlTemplate.ts +25 -0
  94. package/src/templates/android/AndroidNavigationBaseTemplate.ts +46 -0
  95. package/src/templates/android/MessageTemplate.ts +19 -0
  96. package/src/templates/android/NavigationTemplate.ts +50 -0
  97. package/src/templates/android/PaneTemplate.ts +16 -0
  98. package/src/templates/android/PlaceListMapTemplate.ts +64 -0
  99. package/src/templates/android/PlaceListNavigationTemplate.ts +57 -0
  100. package/src/templates/android/RoutePreviewNavigationTemplate.ts +66 -0
@@ -0,0 +1,167 @@
1
+ import { CarPlay } from '../CarPlay';
2
+ import { ListItemUpdate } from '../interfaces/ListItemUpdate';
3
+ import { ListSection } from '../interfaces/ListSection';
4
+ import { Template, TemplateConfig } from './Template';
5
+
6
+ type CollectionType = '' | 'playlist' | 'artist' | 'groupedArtist' | 'editorial' | 'search' | 'user' | 'allTracks' | 'allRecent' | 'allFavorites'
7
+
8
+ export interface ListTemplateConfig extends TemplateConfig {
9
+ /**
10
+ * The title displayed in the navigation bar while the list template is visible.
11
+ */
12
+ title?: string;
13
+ /**
14
+ * The sections displayed in the list.
15
+ */
16
+ sections: ListSection[];
17
+ /**
18
+ * An optional array of strings, ordered from most to least preferred.
19
+ * The variant strings should be provided as localized, displayable content.
20
+ * The system will select the first variant that fits the available space.
21
+ * If the list template does not contain any items (itemCount == 0), then
22
+ * the template will display an empty view with a title and subtitle to indicate
23
+ * that the template has no list items.
24
+ * If the list template is updated to contain items, the empty view will be automatically
25
+ * removed.
26
+ */
27
+ emptyViewTitleVariants?: string[];
28
+ /**
29
+ * An optional array of strings, ordered from most to least preferred.
30
+ * The variant strings should be provided as localized, displayable content.
31
+ * The system will select the first variant that fits the available space.
32
+ * If the list template does not contain any items (itemCount == 0), then
33
+ * the template will display an empty view with a title and subtitle to indicate
34
+ * that the template has no list items.
35
+ * If the list template is updated to contain items, the empty view will be automatically
36
+ * removed.
37
+ */
38
+ emptyViewSubtitleVariants?: string[];
39
+ /**
40
+ * Fired when list item is selected.
41
+ * Spinner shows by default.
42
+ * When the returned promise is resolved the spinner will hide.
43
+ * @param item Object with the selected index
44
+ */
45
+ onItemSelect?(item: { index: number }): Promise<void>;
46
+
47
+ /**
48
+ * Fired when row item is selected.
49
+ * Spinner shows by default.
50
+ * When the returned promise is resolved the spinner will hide.
51
+ * @param item Object with the selected index
52
+ */
53
+ onRowItemSelect?(item: { index: number }): Promise<void>;
54
+
55
+ /**
56
+ * Fired when the template is loaded.
57
+ */
58
+ onTemplateLoaded?(): Promise<void>;
59
+
60
+ /**
61
+ * Fired when the back button is pressed
62
+ */
63
+ onBackButtonPressed?(): void;
64
+
65
+ /**
66
+ * Option to hide back button
67
+ * (defaults to false)
68
+ */
69
+ backButtonHidden?: boolean;
70
+
71
+ /**
72
+ * Back button title
73
+ */
74
+ backButtonTitle: string;
75
+
76
+ /**
77
+ * Assistant Configuration
78
+ * @see https://developer.apple.com/documentation/carplay/cplisttemplate#3762508
79
+ */
80
+ assistant?: {
81
+ enabled: boolean;
82
+ position: 'top' | 'bottom';
83
+ visibility: 'off' | 'always' | 'limited';
84
+ action: 'playMedia' | 'startCall';
85
+ };
86
+
87
+ /**
88
+ * Set to true if you are asynchronously updating an existing template
89
+ */
90
+ updatingTemplate: boolean;
91
+
92
+ /**
93
+ * Set to true if you want to receive the onTemplateLoaded callback
94
+ */
95
+ needsTemplateLoadedCallback: boolean;
96
+ }
97
+
98
+ /**
99
+ * A hierarchical list of menu items can be displayed on the CarPlay screen using a list template.
100
+ *
101
+ * The List Template allows navigation apps to present a hierarchical list of menu items. It includes a navigation bar and a list view.
102
+ *
103
+ * The navigation bar includes a title, and up to two (2) leading buttons and two (2) trailing buttons. You can customize the appearance of these buttons with icons or text.
104
+ *
105
+ * Each item in the list view may include an icon, title, subtitle, and an optional disclosure indicator indicating the presence of a submenu. The depth of the menu hierarchy may not exceed 5 levels. Note that some cars limit the total number of items that may be shown in a list.
106
+ */
107
+ export class ListTemplate extends Template<ListTemplateConfig> {
108
+ public get type(): string {
109
+ return 'list';
110
+ }
111
+
112
+ get eventMap() {
113
+ return {
114
+ backButtonPressed: 'onBackButtonPressed',
115
+ };
116
+ }
117
+
118
+ constructor(public config: ListTemplateConfig) {
119
+ super(config);
120
+
121
+ CarPlay.emitter.addListener('didSelectListItem', e => {
122
+ if (config.onItemSelect && e.templateId === this.id) {
123
+ void Promise.resolve(config.onItemSelect(e)).then(() => {
124
+ CarPlay.bridge.reactToSelectedResult(true);
125
+ });
126
+ }
127
+ });
128
+
129
+ CarPlay.emitter.addListener('didSelectRowItem', e => {
130
+ if (config.onRowItemSelect && e.templateId === this.id) {
131
+ void Promise.resolve(config.onRowItemSelect(e)).then(() => {
132
+ CarPlay.bridge.reactToSelectedResult(true);
133
+ });
134
+ }
135
+ });
136
+
137
+ CarPlay.emitter.addListener('templateLoaded', e => {
138
+ if (config.onTemplateLoaded && e.templateId === this.id) {
139
+ void Promise.resolve(config.onTemplateLoaded())
140
+ }
141
+ });
142
+ }
143
+
144
+ public updateSections = (sections: ListSection[]) => {
145
+ return CarPlay.bridge.updateListTemplateSections(this.id, this.parseConfig(sections));
146
+ };
147
+
148
+ public updateListTemplateItem = (config: ListItemUpdate) => {
149
+ return CarPlay.bridge.updateListTemplateItem(this.id, this.parseConfig(config));
150
+ };
151
+
152
+ public updateListTemplateRowItems = (config: ListItemUpdate) => {
153
+ return CarPlay.bridge.updateListTemplateRowItems(this.id, this.parseConfig(config));
154
+ };
155
+
156
+ public getMaximumListItemCount() {
157
+ return CarPlay.bridge.getMaximumListItemCount(this.id);
158
+ }
159
+
160
+ public getMaximumListSectionCount() {
161
+ return CarPlay.bridge.getMaximumListSectionCount(this.id);
162
+ }
163
+
164
+ public getMaximumRowItemsCount() {
165
+ return CarPlay.bridge.getMaximumRowItemsCount(this.id);
166
+ }
167
+ }
@@ -0,0 +1,231 @@
1
+ import { AppRegistry, Platform } from 'react-native';
2
+ import { CarPlay } from '../CarPlay';
3
+ import { MapButton } from '../interfaces/MapButton';
4
+ import { NavigationAlert } from '../interfaces/NavigationAlert';
5
+ import { TextConfiguration } from '../interfaces/TextConfiguration';
6
+ import { TimeRemainingColor } from '../interfaces/TimeRemainingColor';
7
+ import { TravelEstimates } from '../interfaces/TravelEstimates';
8
+ import { NavigationSession } from '../navigation/NavigationSession';
9
+ import { Trip } from '../navigation/Trip';
10
+ import { Template, TemplateConfig } from './Template';
11
+ import { ListItem } from '../interfaces/ListItem';
12
+ import { Action } from '../interfaces/Action';
13
+ import { Header } from '../interfaces/Header';
14
+ import { Pane } from '../interfaces/Pane';
15
+
16
+ export interface MapTemplateConfig extends TemplateConfig {
17
+ /**
18
+ * The background color the map template uses when displaying guidance.
19
+ * @namespace iOS
20
+ */
21
+ guidanceBackgroundColor?: string;
22
+ /**
23
+ * The style that the map template uses when displaying trip estimates during active nagivation.
24
+ * @default dark
25
+ * @namespace iOS
26
+ */
27
+ tripEstimateStyle?: 'dark' | 'light';
28
+ /**
29
+ * Your component to render inside CarPlay/Android Auto
30
+ * Example `component: MyComponent`
31
+ */
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ component: React.ComponentType<any>;
34
+ /**
35
+ * An array of map buttons displayed on the trailing bottom corner of the map template.
36
+ * If the array contains more than three buttons, the map template displays only the first three buttons, ignoring the remaining buttons.
37
+ * @namespace iOS
38
+ * @namespace Android
39
+ */
40
+ mapButtons?: MapButton[];
41
+ /**
42
+ * A Boolean value that indicates whether the navigation bar hides automatically.
43
+ * @namespace iOS
44
+ */
45
+ automaticallyHidesNavigationBar?: boolean;
46
+ /**
47
+ * A Boolean value that tells the system to hide the map buttons when hiding the navigation bar.
48
+ * @namespace iOS
49
+ */
50
+ hidesButtonsWithNavigationBar?: boolean;
51
+ /**
52
+ * A component that holds onto data associated with a template's header.
53
+ * @namespace Android
54
+ */
55
+ header?: Header;
56
+ /**
57
+ * Sets an ItemList to show in a list view along with the map.
58
+ * - To show a marker corresponding to a point of interest represented by a row, set the Place instance via setMetadata. The host will display the PlaceMarker in both the map and the list view as the row becomes visible.
59
+ * - Images of type IMAGE_TYPE_LARGE are not allowed in this template.
60
+ * - Rows are not allowed to have both an image and a place marker.
61
+ * @limit The number of items in the ItemList should be smaller or equal than the limit provided by CONTENT_LIMIT_TYPE_PLACE_LIST. The host will ignore any items over that limit. The list itself cannot be selectable as set via setOnSelectedListener. Each Row can add up to 2 lines of texts via addText and cannot contain a Toggle.
62
+ * @namespace Android
63
+ */
64
+ items?: ListItem[];
65
+ /**
66
+ * Sets the ActionStrip for this template.
67
+ * Unless set with this method, the template will not have an action strip.
68
+ * The Action buttons in Map Based Template are automatically adjusted based on the screen size. On narrow width screen, icon Actions show by default. If no icon specify, showing title Actions instead. On wider width screen, title Actions show by default. If no title specify, showing icon Actions instead.
69
+ * @limit This template allows up to 4 Actions in its ActionStrip. Of the 4 allowed Actions, it can either be a title Action as set via setTitle, or a icon Action as set via setIcon.
70
+ * @namespace Android
71
+ */
72
+ actions?: Action[];
73
+ /**
74
+ * Sets the Pane for this template. getImage for pane will not be shown in MapTemplate.
75
+ * Unless set with this method, the template will not show a pane.
76
+ * @limit The number of items in the Pane should be smaller or equal than the limit provided by CONTENT_LIMIT_TYPE_PANE. The host via addText and cannot contain either a Toggle or a OnClickListener.
77
+ * Up to 2 Actions are allowed in the Pane. Each action's title color can be customized with ForegroundCarColorSpan instances. Any other span is not supported.
78
+ * If none of the header Action, the header title or the action strip have been set on the template, the header is hidden.
79
+ */
80
+ pane?: Pane;
81
+ /**
82
+ * Fired when Alert Action button is pressed
83
+ * @param e Event
84
+ */
85
+ onAlertActionPressed?(e: { secondary?: boolean; primary?: boolean }): void;
86
+ onMapButtonPressed?(e: { id: string; template: string }): void;
87
+ onPanWithDirection?(e: { direction: string }): void;
88
+ onPanBeganWithDirection?(e: { direction: string }): void;
89
+ onPanEndedWithDirection?(e: { direction: string }): void;
90
+ onSelectedPreviewForTrip?(e: { tripId: string; routeIndex: number }): void;
91
+ onDidCancelNavigation?(): void;
92
+ onStartedTrip?(e: { tripId: string; routeIndex: number }): void;
93
+ }
94
+
95
+ /**
96
+ * The Map Template is a control layer that appears as an overlay over the base view and allows you to present user controls.
97
+ *
98
+ * The control layer consists of a navigation bar and map buttons. By default, the navigation bar appears when the user interacts with the app, and disappears after a period of inactivity.
99
+ *
100
+ * The navigation bar includes up to two leading buttons and two trailing buttons. You can customize the appearance of these buttons with icons or text.
101
+ *
102
+ * The control layer may also include up to four map buttons. The map buttons are always shown as icons.
103
+ *
104
+ * Navigation apps enter panning mode, zoom in or out, and perform other functions by responding to user actions on these buttons.
105
+ */
106
+ export class MapTemplate extends Template<MapTemplateConfig> {
107
+ public get type(): string {
108
+ return 'map';
109
+ }
110
+
111
+ get eventMap() {
112
+ return {
113
+ alertActionPressed: 'onAlertActionPressed',
114
+ mapButtonPressed: 'onMapButtonPressed',
115
+ panWithDirection: 'onPanWithDirection',
116
+ panBeganWithDirection: 'onPanBeganWithDirection',
117
+ panEndedWithDirection: 'onPanEndedWithDirection',
118
+ selectedPreviewForTrip: 'onSelectedPreviewForTrip',
119
+ didCancelNavigation: 'onDidCancelNavigation',
120
+ startedTrip: 'onStartedTrip',
121
+ };
122
+ }
123
+
124
+ constructor(public config: MapTemplateConfig) {
125
+ super(config);
126
+
127
+ if (config.component) {
128
+ AppRegistry.registerComponent(this.id, () => config.component);
129
+ }
130
+
131
+ const callbackFn = Platform.select({
132
+ android: ({ error }: { error?: string } = {}) => {
133
+ error && console.error(error);
134
+ },
135
+ });
136
+
137
+ CarPlay.bridge.createTemplate(
138
+ this.id,
139
+ this.parseConfig({ type: this.type, ...config, render: true }),
140
+ callbackFn,
141
+ );
142
+ }
143
+
144
+ /**
145
+ * Begins guidance for a trip.
146
+ *
147
+ * Keep a reference to the navigation session to perform guidance updates.
148
+ * @param trip Trip class instance
149
+ */
150
+ public async startNavigationSession(trip: Trip): Promise<NavigationSession> {
151
+ const res = await CarPlay.bridge.startNavigationSession(this.id, trip.id);
152
+ return new NavigationSession(res.navigationSessionId, trip, this);
153
+ }
154
+
155
+ public updateTravelEstimates(
156
+ trip: Trip,
157
+ travelEstimates: TravelEstimates,
158
+ timeRemainingColor: TimeRemainingColor = 0,
159
+ ) {
160
+ if (!travelEstimates.distanceUnits) {
161
+ travelEstimates.distanceUnits = 'kilometers';
162
+ }
163
+ CarPlay.bridge.updateTravelEstimatesForTrip(
164
+ this.id,
165
+ trip.id,
166
+ travelEstimates,
167
+ timeRemainingColor,
168
+ );
169
+ }
170
+ /**
171
+ * Update MapTemplate configuration
172
+ */
173
+ public updateConfig(config: MapTemplateConfig) {
174
+ this.config = config;
175
+ CarPlay.bridge.updateMapTemplateConfig(this.id, this.parseConfig(config));
176
+ }
177
+
178
+ public updateMapButtons(mapButtons: MapButton[]) {
179
+ this.config.mapButtons = mapButtons;
180
+ CarPlay.bridge.updateMapTemplateMapButtons(this.id, this.parseConfig(mapButtons));
181
+ }
182
+
183
+ /**
184
+ * Hides the display of trip previews.
185
+ */
186
+ public hideTripPreviews() {
187
+ CarPlay.bridge.hideTripPreviews(this.id);
188
+ }
189
+
190
+ public showTripPreviews(tripPreviews: Trip[], textConfiguration: TextConfiguration = {}) {
191
+ CarPlay.bridge.showTripPreviews(
192
+ this.id,
193
+ tripPreviews.map(trip => trip.id),
194
+ textConfiguration,
195
+ );
196
+ }
197
+
198
+ public showRouteChoicesPreviewForTrip(trip: Trip, textConfiguration: TextConfiguration = {}) {
199
+ CarPlay.bridge.showRouteChoicesPreviewForTrip(this.id, trip.id, textConfiguration);
200
+ }
201
+
202
+ public presentNavigationAlert(config: NavigationAlert, animated = true) {
203
+ CarPlay.bridge.presentNavigationAlert(this.id, config, animated);
204
+ }
205
+
206
+ public dismissNavigationAlert(animated = true) {
207
+ CarPlay.bridge.dismissNavigationAlert(this.id, animated);
208
+ }
209
+
210
+ /**
211
+ * Shows the panning interface over the map.
212
+ *
213
+ * Calling this method while displaying the panning interface has no effect.
214
+ *
215
+ * While showing the panning interface, the system hides all map buttons. The system doesn't provide a button to dismiss the panning interface. Instead, you must provide a map button in the navigation bar that the user taps to dismiss the panning interface.
216
+ * @param animated A Boolean value that determines whether to animate the panning interface.
217
+ */
218
+ public showPanningInterface(animated = false) {
219
+ CarPlay.bridge.showPanningInterface(this.id, animated);
220
+ }
221
+
222
+ /**
223
+ * Dismisses the panning interface.
224
+ *
225
+ * When dismissing the panning interface, the system shows the previously hidden map buttons.
226
+ * @param animated A Boolean value that determines whether to animate the dismissal of the panning interface.
227
+ */
228
+ public dismissPanningInterface(animated = false) {
229
+ CarPlay.bridge.dismissPanningInterface(this.id, animated);
230
+ }
231
+ }
@@ -0,0 +1,31 @@
1
+ import { Template, TemplateConfig } from './Template';
2
+
3
+ export type NowPlayingButton = {
4
+ id: string;
5
+ imageName: string;
6
+ selected: boolean;
7
+ };
8
+
9
+ export interface NowPlayingTemplateConfig extends TemplateConfig {
10
+ albumArtistButtonEnabled?: boolean;
11
+ upNextButtonTitle?: string;
12
+ upNextButtonEnabled?: boolean;
13
+ onAlbumArtistButtonPressed?(): void;
14
+ onUpNextButtonPressed?(): void;
15
+ onButtonPressed?(e: { id: string; templateId: string }): void;
16
+ buttons?: NowPlayingButton[];
17
+ }
18
+
19
+ export class NowPlayingTemplate extends Template<NowPlayingTemplateConfig> {
20
+ public get type(): string {
21
+ return 'nowplaying';
22
+ }
23
+
24
+ get eventMap() {
25
+ return {
26
+ albumArtistButtonPressed: 'onAlbumArtistButtonPressed',
27
+ upNextButtonPressed: 'onUpNextButtonPressed',
28
+ buttonPressed: 'onButtonPressed',
29
+ };
30
+ }
31
+ }
@@ -0,0 +1,40 @@
1
+ import { Template, TemplateConfig } from './Template';
2
+
3
+ export interface PointOfInterestItem {
4
+ id: string;
5
+ location: {
6
+ latitude: number;
7
+ longitude: number;
8
+ };
9
+ title: string;
10
+ subtitle?: string;
11
+ summary?: string;
12
+ detailTitle?: string;
13
+ detailSubtitle?: string;
14
+ detailSummary?: string;
15
+ }
16
+
17
+ export interface PointOfInterestTemplateConfig extends TemplateConfig {
18
+ title: string;
19
+ items: PointOfInterestItem[];
20
+ onPointOfInterestSelect?(e: PointOfInterestItem): void;
21
+ onChangeMapRegion(e: {
22
+ latitude: number;
23
+ longitude: number;
24
+ latitudeDelta: number;
25
+ longitudeDelta: number;
26
+ }): void;
27
+ }
28
+
29
+ export class PointOfInterestTemplate extends Template<PointOfInterestTemplateConfig> {
30
+ public get type(): string {
31
+ return 'poi';
32
+ }
33
+
34
+ get eventMap() {
35
+ return {
36
+ didSelectPointOfInterest: 'onPointOfInterestSelect',
37
+ didChangeMapRegion: 'onChangeMapRegion',
38
+ };
39
+ }
40
+ }
@@ -0,0 +1,70 @@
1
+ import { CarPlay } from '../CarPlay';
2
+ import { ListItem } from '../interfaces/ListItem';
3
+ import { BaseEvent, Template, TemplateConfig } from './Template';
4
+ import { Image, Platform } from 'react-native';
5
+
6
+ export interface SearchTemplateConfig extends TemplateConfig {
7
+ /**
8
+ * Fired when search input is changed.
9
+ * Must return list of items to show.
10
+ * @param query Search query
11
+ */
12
+ onSearch?(query: string): Promise<ListItem[]>;
13
+ /**
14
+ * Fired when result item is selected.
15
+ * Spinner shows by default.
16
+ * When the returned promise is resolved the spinner will hide.
17
+ * @param item Object with the selected index
18
+ */
19
+ onItemSelect?(item: { index: number }): Promise<void>;
20
+ /**
21
+ * Fired when search button is pressed
22
+ */
23
+ onSearchButtonPressed?(e: BaseEvent): void;
24
+ }
25
+
26
+ export class SearchTemplate extends Template<SearchTemplateConfig> {
27
+ public get type(): string {
28
+ return 'search';
29
+ }
30
+
31
+ get eventMap() {
32
+ return {
33
+ searchButtonPressed: 'onSearchButtonPressed',
34
+ };
35
+ }
36
+
37
+ constructor(public config: SearchTemplateConfig) {
38
+ // parse out any images in the results
39
+
40
+ super(config);
41
+
42
+ CarPlay.emitter.addListener(
43
+ 'updatedSearchText',
44
+ (e: { searchText: string; templateId: string }) => {
45
+ if (config.onSearch && e.templateId === this.id) {
46
+ void Promise.resolve(config.onSearch(e.searchText)).then((result = []) => {
47
+ if (Platform.OS === 'ios') {
48
+ const parsedResults = result.map(item => ({
49
+ ...item,
50
+ image: item.image ? Image.resolveAssetSource(item.image) : undefined,
51
+ }));
52
+ CarPlay.bridge.reactToUpdatedSearchText(parsedResults);
53
+ }
54
+ });
55
+ }
56
+ },
57
+ );
58
+
59
+ CarPlay.emitter.addListener(
60
+ 'selectedResult',
61
+ (e: { templateId: string; index: number; id?: string }) => {
62
+ if (config.onItemSelect && e.templateId === this.id) {
63
+ void Promise.resolve(config.onItemSelect(e)).then(
64
+ () => Platform.OS === 'ios' && CarPlay.bridge.reactToSelectedResult(true),
65
+ );
66
+ }
67
+ },
68
+ );
69
+ }
70
+ }
@@ -0,0 +1,56 @@
1
+ import { CarPlay } from '../CarPlay';
2
+ import { GridTemplate } from './GridTemplate';
3
+ import { InformationTemplate } from './InformationTemplate';
4
+ import { ListTemplate } from './ListTemplate';
5
+ import { PointOfInterestTemplate } from './PointOfInterestTemplate';
6
+ import { Template, TemplateConfig } from './Template';
7
+
8
+ export type TabBarTemplates =
9
+ | ListTemplate
10
+ | GridTemplate
11
+ | InformationTemplate
12
+ | PointOfInterestTemplate;
13
+
14
+ export interface TabBarTemplateConfig extends TemplateConfig {
15
+ /**
16
+ * The title displayed in the navigation bar while the tab bar template is visible.
17
+ */
18
+ title?: string;
19
+ /**
20
+ * The templates to show as tabs.
21
+ */
22
+ templates: TabBarTemplates[];
23
+
24
+ onTemplateSelect(
25
+ template: TabBarTemplates | undefined,
26
+ e: { templateId: string; selectedTemplateId: string },
27
+ ): void;
28
+ }
29
+
30
+ /**/
31
+ export class TabBarTemplate extends Template<TabBarTemplateConfig> {
32
+ public get type(): string {
33
+ return 'tabbar';
34
+ }
35
+
36
+ constructor(public config: TabBarTemplateConfig) {
37
+ super(config);
38
+
39
+ CarPlay.emitter.addListener(
40
+ 'didSelectTemplate',
41
+ (e: { templateId: string; selectedTemplateId: string }) => {
42
+ if (config.onTemplateSelect && e.templateId === this.id) {
43
+ config.onTemplateSelect(
44
+ config.templates.find(tpl => tpl.id === e.selectedTemplateId),
45
+ e,
46
+ );
47
+ }
48
+ },
49
+ );
50
+ }
51
+
52
+ public updateTemplates = (config: TabBarTemplateConfig) => {
53
+ this.config = config;
54
+ return CarPlay.bridge.updateTabBarTemplates(this.id, this.parseConfig(config));
55
+ };
56
+ }