Skip to content

Commit 3213da4

Browse files
committed
feat(ios): refactor list template handlers from deprecated delegate and add item/image ids to handler
1 parent 0b48fcd commit 3213da4

File tree

4 files changed

+196
-34
lines changed

4 files changed

+196
-34
lines changed

packages/react-native-carplay/ios/RNCarPlay.m

Lines changed: 118 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ - (void)updateListRowItemImageWithURL:(CPListImageRowItem *)item imgUrl:(NSStrin
281281
listTemplate.emptyViewSubtitleVariants = [RCTConvert NSArray:config[@"emptyViewSubtitleVariants"]];
282282
}
283283
}
284-
listTemplate.delegate = self;
285284
carPlayTemplate = listTemplate;
286285
}
287286
else if ([type isEqualToString:@"map"]) {
@@ -1142,6 +1141,17 @@ - (void) applyConfigForMapTemplate:(CPMapTemplate*)mapTemplate templateId:(NSStr
11421141

11431142
NSArray *_imageItems = [item objectForKey:@"images"];
11441143
NSArray *_imageUrls = [item objectForKey:@"imgUrls"];
1144+
NSArray *_imageIds = [item objectForKey:@"imageIds"];
1145+
1146+
NSString *_itemId = [item objectForKey:@"id"];
1147+
1148+
if (_itemId == nil) {
1149+
_itemId = (id)[NSNull null];
1150+
}
1151+
1152+
if (_imageIds == nil) {
1153+
_imageIds = (id)[NSNull null];
1154+
}
11451155

11461156
if (_imageItems == nil && _imageUrls == nil) {
11471157
UIImage *_image = [RCTConvert UIImage:_imageObj];
@@ -1163,8 +1173,37 @@ - (void) applyConfigForMapTemplate:(CPMapTemplate*)mapTemplate templateId:(NSStr
11631173
NSString *imgUrlString = [RCTConvert NSString:item[@"imgUrl"]];
11641174
[self updateItemImageWithURL:_item imgUrl:imgUrlString];
11651175
}
1166-
[_item setUserInfo:@{ @"index": @(listIndex) }];
1167-
[_items addObject:_item];
1176+
[_item setUserInfo:@{
1177+
@"index": @(listIndex),
1178+
@"itemId": _itemId
1179+
}];
1180+
1181+
_item.handler = ^(CPListItem *selectedItem, void (^completionHandler)(void)) {
1182+
NSDictionary *payload = @{
1183+
@"templateId": templateId,
1184+
@"index": selectedItem.userInfo[@"index"],
1185+
@"itemId": selectedItem.userInfo[@"itemId"]
1186+
};
1187+
if (self->hasListeners) {
1188+
[self sendEventWithName:@"didSelectListItem" body:payload];
1189+
}
1190+
self.selectedResultBlock = completionHandler;
1191+
};
1192+
if (_itemId) {
1193+
RNCPStore *store = [RNCPStore sharedManager];
1194+
NSMutableArray *existing = store.itemsStore[_itemId];
1195+
if (existing == nil) {
1196+
existing = [NSMutableArray array];
1197+
store.itemsStore[_itemId] = existing;
1198+
}
1199+
[existing addObject:_item];
1200+
}
1201+
1202+
if (_item) {
1203+
[_items addObject:_item];
1204+
} else {
1205+
NSLog(@"The item was nil can't be created %@", item);
1206+
}
11681207
} else {
11691208
// parse images
11701209
NSMutableArray * _images = [NSMutableArray array];
@@ -1204,17 +1243,68 @@ - (void) applyConfigForMapTemplate:(CPMapTemplate*)mapTemplate templateId:(NSStr
12041243
}
12051244
}
12061245

1246+
[_item setUserInfo:@{
1247+
@"index": @(listIndex),
1248+
@"itemId": _itemId,
1249+
@"imageIds": _imageIds
1250+
}];
1251+
12071252
[_item setListImageRowHandler:^(CPListImageRowItem * _Nonnull item, NSInteger index, dispatch_block_t _Nonnull completionBlock) {
12081253
// Find the current template
12091254
RNCPStore *store = [RNCPStore sharedManager];
12101255
CPTemplate *template = [store findTemplateById:templateId];
1256+
NSString *imageId = nil;
1257+
1258+
id imageIdsObj = item.userInfo[@"imageIds"];
1259+
if ([imageIdsObj isKindOfClass:[NSArray class]]) {
1260+
NSArray *imageIds = (NSArray *)imageIdsObj;
1261+
if (index < imageIds.count) {
1262+
id candidate = imageIds[index];
1263+
if ([candidate isKindOfClass:[NSString class]]) {
1264+
imageId = candidate;
1265+
}
1266+
}
1267+
}
1268+
1269+
if (!imageId) {
1270+
imageId = (NSString *)[NSNull null];
1271+
}
1272+
12111273
if (template) {
1212-
[self sendTemplateEventWithName:template name:@"didSelectListItemRowImage" json:@{ @"index": @(listIndex), @"imageIndex": @(index)}];
1274+
NSMutableDictionary *payload = [@{
1275+
@"index": @(listIndex),
1276+
@"imageIndex": @(index),
1277+
@"itemId": item.userInfo[@"itemId"],
1278+
} mutableCopy];
1279+
1280+
if (![imageId isKindOfClass:[NSNull class]]) {
1281+
payload[@"imageId"] = imageId;
1282+
}
1283+
1284+
[self sendTemplateEventWithName:template
1285+
name:@"didSelectListItemRowImage"
1286+
json:payload];
12131287
}
12141288
}];
12151289

1216-
[_item setUserInfo:@{ @"index": @(listIndex) }];
1217-
[_items addObject:_item];
1290+
_item.handler = ^(CPListItem *selectedItem, void (^completionHandler)(void)) {
1291+
NSDictionary *payload = @{
1292+
@"templateId": templateId,
1293+
@"index": selectedItem.userInfo[@"index"],
1294+
@"itemId": selectedItem.userInfo[@"itemId"]
1295+
};
1296+
1297+
if (self->hasListeners) {
1298+
[self sendEventWithName:@"didSelectListItem" body:payload];
1299+
}
1300+
1301+
self.selectedResultBlock = completionHandler;
1302+
};
1303+
if (_item) {
1304+
[_items addObject:_item];
1305+
} else {
1306+
NSLog(@"The image row item could not be created: %@", item);
1307+
}
12181308
}
12191309

12201310
}
@@ -1433,10 +1523,28 @@ - (void)sendTemplateEventWithName:(CPTemplate *)template name:(NSString*)name {
14331523
[self sendTemplateEventWithName:template name:name json:@{}];
14341524
}
14351525

1436-
- (void)sendTemplateEventWithName:(CPTemplate *)template name:(NSString*)name json:(NSDictionary*)json {
1437-
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:json];
1438-
NSDictionary *userInfo = [template userInfo];
1439-
[body setObject:[userInfo objectForKey:@"templateId"] forKey:@"templateId"];
1526+
- (void)sendTemplateEventWithName:(CPTemplate *)template name:(NSString *)name json:(NSDictionary *)json {
1527+
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:json ?: @{}];
1528+
1529+
NSString *templateId = nil;
1530+
NSDictionary *userInfo = nil;
1531+
1532+
if ([template respondsToSelector:@selector(userInfo)]) {
1533+
userInfo = [template userInfo];
1534+
}
1535+
1536+
if ([userInfo isKindOfClass:[NSDictionary class]]) {
1537+
id value = userInfo[@"templateId"];
1538+
if ([value isKindOfClass:[NSString class]]) {
1539+
templateId = (NSString *)value;
1540+
}
1541+
}
1542+
1543+
if (templateId.length > 0) {
1544+
body[@"templateId"] = templateId;
1545+
}
1546+
body[@"templateId"] = templateId ?: @"";
1547+
14401548
if (hasListeners) {
14411549
[self sendEventWithName:name body:body];
14421550
}
@@ -1538,14 +1646,6 @@ - (void)searchTemplate:(CPSearchTemplate *)searchTemplate updatedSearchText:(NSS
15381646
self.searchResultBlock = completionHandler;
15391647
}
15401648

1541-
# pragma ListTemplate
1542-
1543-
- (void)listTemplate:(CPListTemplate *)listTemplate didSelectListItem:(CPListItem *)item completionHandler:(void (^)(void))completionHandler {
1544-
NSNumber* index = [item.userInfo objectForKey:@"index"];
1545-
[self sendTemplateEventWithName:listTemplate name:@"didSelectListItem" json:@{ @"index": index }];
1546-
self.selectedResultBlock = completionHandler;
1547-
}
1548-
15491649
# pragma TabBarTemplate
15501650
- (void)tabBarTemplate:(CPTabBarTemplate *)tabBarTemplate didSelectTemplate:(__kindof CPTemplate *)selectedTemplate {
15511651
NSString* selectedTemplateId = [[selectedTemplate userInfo] objectForKey:@"templateId"];

packages/react-native-carplay/src/CarPlay.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,21 +158,62 @@ export class CarPlayInterface {
158158
*/
159159
public emitter = new NativeEventEmitter(RNCarPlay);
160160

161+
public selectListItemListenerMap = new Map<
162+
string,
163+
(e: { templateId: string; index: number; itemId?: string }) => void
164+
>();
165+
public selectListItemRowImageListenerMap = new Map<
166+
string,
167+
(e: {
168+
templateId: string;
169+
index: number;
170+
itemId?: string;
171+
imageIndex: number;
172+
imageId?: string;
173+
}) => void
174+
>();
175+
161176
private onConnectCallbacks = new Set<OnConnectCallback>();
162177
private onDisconnectCallbacks = new Set<OnDisconnectCallback>();
163178

164179
constructor() {
165180
this.emitter.addListener('didConnect', (window: WindowInformation) => {
166-
console.log('we are connected yes!');
181+
console.log('Carplay Connected');
167182
this.connected = true;
168183
this.window = window;
184+
this.emitter.addListener(
185+
'didSelectListItem',
186+
(e: { templateId: string; index: number; itemId?: string }) => {
187+
const templateListener = this.selectListItemListenerMap.get(e.templateId);
188+
if (templateListener) {
189+
templateListener(e);
190+
}
191+
},
192+
);
193+
this.emitter.addListener(
194+
'didSelectListItemRowImage',
195+
(e: {
196+
templateId: string;
197+
index: number;
198+
itemId?: string;
199+
imageIndex: number;
200+
imageId?: string;
201+
}) => {
202+
const templateListener = this.selectListItemRowImageListenerMap.get(e.templateId);
203+
if (templateListener) {
204+
templateListener(e);
205+
}
206+
},
207+
);
169208
this.onConnectCallbacks.forEach(callback => {
170209
callback(window);
171210
});
172211
});
173212
this.emitter.addListener('didDisconnect', () => {
174213
this.connected = false;
175214
this.window = undefined;
215+
this.emitter.removeAllListeners('didSelectListItem');
216+
this.emitter.removeAllListeners('didSelectListItemRowImage');
176217
this.onDisconnectCallbacks.forEach(callback => {
177218
callback();
178219
});

packages/react-native-carplay/src/interfaces/ListItem.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ export interface ListItem {
3535
* @namespace iOS
3636
*/
3737
imgUrls?: string[];
38+
/**
39+
* ids corresponding to the images in imgUrls or images which will be passed back on list row item selected
40+
* @namespace iOS
41+
*/
42+
imageIds?: string[];
3843
/**
3944
* A Boolean value indicating whether the list item cell shows a disclosure indicator on the trailing edge of the list item cell.
4045
* @namespace iOS

packages/react-native-carplay/src/templates/ListTemplate.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ export interface ListTemplateConfig extends TemplateConfig {
5050
* When the returned promise is resolved the spinner will hide.
5151
* @param item Object with the selected index
5252
*/
53-
onItemSelect?(item: { templateId: string; index: number }): Promise<void>;
53+
onItemSelect?(
54+
item: {
55+
templateId: string;
56+
index: number;
57+
itemId?: string;
58+
}): Promise<void>;
5459

5560
/**
5661
* Fired when image row item is selected.
@@ -61,7 +66,9 @@ export interface ListTemplateConfig extends TemplateConfig {
6166
onImageRowItemSelect?(item: {
6267
templateId: string;
6368
index: number;
69+
itemId?: string;
6470
imageIndex: number;
71+
imageId?: string;
6572
}): Promise<void>;
6673

6774
/**
@@ -128,20 +135,29 @@ export class ListTemplate extends Template<ListTemplateConfig> {
128135
constructor(public config: ListTemplateConfig) {
129136
super(config);
130137

131-
CarPlay.emitter.addListener('didSelectListItem', (e: { templateId: string; index: number }) => {
132-
if (config.onItemSelect && e.templateId === this.id) {
133-
void Promise.resolve(config.onItemSelect(e)).then(() => {
134-
if (Platform.OS === 'ios') {
135-
CarPlay.bridge.reactToSelectedResult(true);
136-
}
137-
});
138-
}
139-
});
140-
141-
CarPlay.emitter.addListener(
142-
'didSelectListItemRowImage',
143-
(e: { templateId: string; index: number; imageIndex: number }) => {
144-
if (config.onImageRowItemSelect && e.templateId === this.id) {
138+
CarPlay.selectListItemListenerMap.set(
139+
this.id,
140+
(e: { templateId: string; index: number; itemId?: string }) => {
141+
if (config.onItemSelect) {
142+
void Promise.resolve(config.onItemSelect(e)).then(() => {
143+
if (Platform.OS === 'ios') {
144+
CarPlay.bridge.reactToSelectedResult(true);
145+
}
146+
});
147+
}
148+
},
149+
);
150+
151+
CarPlay.selectListItemRowImageListenerMap.set(
152+
this.id,
153+
(e: {
154+
templateId: string;
155+
index: number;
156+
itemId?: string;
157+
imageIndex: number;
158+
imageId?: string;
159+
}) => {
160+
if (config.onImageRowItemSelect) {
145161
void Promise.resolve(config.onImageRowItemSelect(e)).then(() => {
146162
if (Platform.OS === 'ios') {
147163
CarPlay.bridge.reactToSelectedResult(true);

0 commit comments

Comments
 (0)