@santoshpk/react-native-carplay 1.0.3
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.
- package/README.md +119 -0
- package/android/.idea/compiler.xml +6 -0
- package/android/.idea/gradle.xml +17 -0
- package/android/.idea/jarRepositories.xml +25 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/build.gradle +63 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradle.properties +20 -0
- package/android/gradlew +234 -0
- package/android/gradlew.bat +89 -0
- package/android/local.properties +8 -0
- package/android/src/main/AndroidManifest.xml +31 -0
- package/android/src/main/AndroidManifestNew.xml +31 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayModule.kt +348 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayPackage.kt +18 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayService.kt +34 -0
- package/android/src/main/java/org/birkir/carplay/CarPlaySession.kt +114 -0
- package/android/src/main/java/org/birkir/carplay/parser/Ext.kt +11 -0
- package/android/src/main/java/org/birkir/carplay/parser/Parser.kt +18 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTGridTemplate.kt +28 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTListTemplate.kt +64 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTMapTemplate.kt +185 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTMessageTemplate.kt +36 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTPaneTemplate.kt +24 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTSearchTemplate.kt +41 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTTabTemplate.kt +52 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTTemplate.kt +434 -0
- package/android/src/main/java/org/birkir/carplay/parser/TemplateParser.kt +35 -0
- package/android/src/main/java/org/birkir/carplay/screens/CarScreen.kt +69 -0
- package/android/src/main/java/org/birkir/carplay/screens/CarScreenContext.kt +10 -0
- package/android/src/main/java/org/birkir/carplay/utils/EventEmitter.kt +174 -0
- package/android/src/main/java/org/birkir/carplay/utils/VirtualRenderer.kt +75 -0
- package/ios/RCTConvert+RNCarPlay.h +18 -0
- package/ios/RCTConvert+RNCarPlay.m +96 -0
- package/ios/RNCPStore.h +24 -0
- package/ios/RNCPStore.m +68 -0
- package/ios/RNCarPlay.h +29 -0
- package/ios/RNCarPlay.m +1839 -0
- package/ios/RNCarPlay.xcodeproj/project.pbxproj +300 -0
- package/lib/CarPlay.d.ts +196 -0
- package/lib/CarPlay.d.ts.map +1 -0
- package/lib/CarPlay.js +176 -0
- package/lib/CarPlay.js.map +1 -0
- package/lib/index.d.ts +44 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +64 -0
- package/lib/index.js.map +1 -0
- package/lib/interfaces/Action.d.ts +13 -0
- package/lib/interfaces/Action.d.ts.map +1 -0
- package/lib/interfaces/Action.js +3 -0
- package/lib/interfaces/Action.js.map +1 -0
- package/lib/interfaces/AlertAction.d.ts +6 -0
- package/lib/interfaces/AlertAction.d.ts.map +1 -0
- package/lib/interfaces/AlertAction.js +3 -0
- package/lib/interfaces/AlertAction.js.map +1 -0
- package/lib/interfaces/BarButton.d.ts +39 -0
- package/lib/interfaces/BarButton.d.ts.map +1 -0
- package/lib/interfaces/BarButton.js +3 -0
- package/lib/interfaces/BarButton.js.map +1 -0
- package/lib/interfaces/CarColor.d.ts +2 -0
- package/lib/interfaces/CarColor.d.ts.map +1 -0
- package/lib/interfaces/CarColor.js +3 -0
- package/lib/interfaces/CarColor.js.map +1 -0
- package/lib/interfaces/GridButton.d.ts +24 -0
- package/lib/interfaces/GridButton.d.ts.map +1 -0
- package/lib/interfaces/GridButton.js +3 -0
- package/lib/interfaces/GridButton.js.map +1 -0
- package/lib/interfaces/Header.d.ts +15 -0
- package/lib/interfaces/Header.d.ts.map +1 -0
- package/lib/interfaces/Header.js +3 -0
- package/lib/interfaces/Header.js.map +1 -0
- package/lib/interfaces/ListItem.d.ts +61 -0
- package/lib/interfaces/ListItem.d.ts.map +1 -0
- package/lib/interfaces/ListItem.js +3 -0
- package/lib/interfaces/ListItem.js.map +1 -0
- package/lib/interfaces/ListItemUpdate.d.ts +15 -0
- package/lib/interfaces/ListItemUpdate.d.ts.map +1 -0
- package/lib/interfaces/ListItemUpdate.js +3 -0
- package/lib/interfaces/ListItemUpdate.js.map +1 -0
- package/lib/interfaces/ListSection.d.ts +21 -0
- package/lib/interfaces/ListSection.d.ts.map +1 -0
- package/lib/interfaces/ListSection.js +3 -0
- package/lib/interfaces/ListSection.js.map +1 -0
- package/lib/interfaces/Maneuver.d.ts +31 -0
- package/lib/interfaces/Maneuver.d.ts.map +1 -0
- package/lib/interfaces/Maneuver.js +3 -0
- package/lib/interfaces/Maneuver.js.map +1 -0
- package/lib/interfaces/MapButton.d.ts +27 -0
- package/lib/interfaces/MapButton.d.ts.map +1 -0
- package/lib/interfaces/MapButton.js +3 -0
- package/lib/interfaces/MapButton.js.map +1 -0
- package/lib/interfaces/NavigationAlert.d.ts +44 -0
- package/lib/interfaces/NavigationAlert.d.ts.map +1 -0
- package/lib/interfaces/NavigationAlert.js +10 -0
- package/lib/interfaces/NavigationAlert.js.map +1 -0
- package/lib/interfaces/NavigationInfo.d.ts +17 -0
- package/lib/interfaces/NavigationInfo.d.ts.map +1 -0
- package/lib/interfaces/NavigationInfo.js +3 -0
- package/lib/interfaces/NavigationInfo.js.map +1 -0
- package/lib/interfaces/NavigationStep.d.ts +17 -0
- package/lib/interfaces/NavigationStep.d.ts.map +1 -0
- package/lib/interfaces/NavigationStep.js +3 -0
- package/lib/interfaces/NavigationStep.js.map +1 -0
- package/lib/interfaces/Pane.d.ts +29 -0
- package/lib/interfaces/Pane.d.ts.map +1 -0
- package/lib/interfaces/Pane.js +3 -0
- package/lib/interfaces/Pane.js.map +1 -0
- package/lib/interfaces/PauseReason.d.ts +8 -0
- package/lib/interfaces/PauseReason.d.ts.map +1 -0
- package/lib/interfaces/PauseReason.js +12 -0
- package/lib/interfaces/PauseReason.js.map +1 -0
- package/lib/interfaces/Place.d.ts +11 -0
- package/lib/interfaces/Place.d.ts.map +1 -0
- package/lib/interfaces/Place.js +3 -0
- package/lib/interfaces/Place.js.map +1 -0
- package/lib/interfaces/TextConfiguration.d.ts +6 -0
- package/lib/interfaces/TextConfiguration.d.ts.map +1 -0
- package/lib/interfaces/TextConfiguration.js +3 -0
- package/lib/interfaces/TextConfiguration.js.map +1 -0
- package/lib/interfaces/TimeRemainingColor.d.ts +2 -0
- package/lib/interfaces/TimeRemainingColor.d.ts.map +1 -0
- package/lib/interfaces/TimeRemainingColor.js +3 -0
- package/lib/interfaces/TimeRemainingColor.js.map +1 -0
- package/lib/interfaces/TravelEstimates.d.ts +37 -0
- package/lib/interfaces/TravelEstimates.d.ts.map +1 -0
- package/lib/interfaces/TravelEstimates.js +3 -0
- package/lib/interfaces/TravelEstimates.js.map +1 -0
- package/lib/interfaces/VoiceControlState.d.ts +8 -0
- package/lib/interfaces/VoiceControlState.d.ts.map +1 -0
- package/lib/interfaces/VoiceControlState.js +3 -0
- package/lib/interfaces/VoiceControlState.js.map +1 -0
- package/lib/navigation/NavigationSession.d.ts +18 -0
- package/lib/navigation/NavigationSession.d.ts.map +1 -0
- package/lib/navigation/NavigationSession.js +51 -0
- package/lib/navigation/NavigationSession.js.map +1 -0
- package/lib/navigation/Trip.d.ts +22 -0
- package/lib/navigation/Trip.d.ts.map +1 -0
- package/lib/navigation/Trip.js +18 -0
- package/lib/navigation/Trip.js.map +1 -0
- package/lib/templates/ActionSheetTemplate.d.ts +18 -0
- package/lib/templates/ActionSheetTemplate.d.ts.map +1 -0
- package/lib/templates/ActionSheetTemplate.js +16 -0
- package/lib/templates/ActionSheetTemplate.js.map +1 -0
- package/lib/templates/AlertTemplate.d.ts +17 -0
- package/lib/templates/AlertTemplate.d.ts.map +1 -0
- package/lib/templates/AlertTemplate.js +16 -0
- package/lib/templates/AlertTemplate.js.map +1 -0
- package/lib/templates/ContactTemplate.d.ts +36 -0
- package/lib/templates/ContactTemplate.d.ts.map +1 -0
- package/lib/templates/ContactTemplate.js +16 -0
- package/lib/templates/ContactTemplate.js.map +1 -0
- package/lib/templates/GridTemplate.d.ts +38 -0
- package/lib/templates/GridTemplate.d.ts.map +1 -0
- package/lib/templates/GridTemplate.js +17 -0
- package/lib/templates/GridTemplate.js.map +1 -0
- package/lib/templates/InformationTemplate.d.ts +28 -0
- package/lib/templates/InformationTemplate.d.ts.map +1 -0
- package/lib/templates/InformationTemplate.js +28 -0
- package/lib/templates/InformationTemplate.js.map +1 -0
- package/lib/templates/ListTemplate.d.ts +112 -0
- package/lib/templates/ListTemplate.d.ts.map +1 -0
- package/lib/templates/ListTemplate.js +57 -0
- package/lib/templates/ListTemplate.js.map +1 -0
- package/lib/templates/MapTemplate.d.ts +171 -0
- package/lib/templates/MapTemplate.d.ts.map +1 -0
- package/lib/templates/MapTemplate.js +115 -0
- package/lib/templates/MapTemplate.js.map +1 -0
- package/lib/templates/NowPlayingTemplate.d.ts +31 -0
- package/lib/templates/NowPlayingTemplate.d.ts.map +1 -0
- package/lib/templates/NowPlayingTemplate.js +18 -0
- package/lib/templates/NowPlayingTemplate.js.map +1 -0
- package/lib/templates/PointOfInterestTemplate.d.ts +38 -0
- package/lib/templates/PointOfInterestTemplate.d.ts.map +1 -0
- package/lib/templates/PointOfInterestTemplate.js +18 -0
- package/lib/templates/PointOfInterestTemplate.js.map +1 -0
- package/lib/templates/SearchTemplate.d.ts +32 -0
- package/lib/templates/SearchTemplate.d.ts.map +1 -0
- package/lib/templates/SearchTemplate.js +41 -0
- package/lib/templates/SearchTemplate.js.map +1 -0
- package/lib/templates/TabBarTemplate.d.ts +27 -0
- package/lib/templates/TabBarTemplate.d.ts.map +1 -0
- package/lib/templates/TabBarTemplate.js +26 -0
- package/lib/templates/TabBarTemplate.js.map +1 -0
- package/lib/templates/Template.d.ts +83 -0
- package/lib/templates/Template.d.ts.map +1 -0
- package/lib/templates/Template.js +71 -0
- package/lib/templates/Template.js.map +1 -0
- package/lib/templates/VoiceControlTemplate.d.ts +18 -0
- package/lib/templates/VoiceControlTemplate.d.ts.map +1 -0
- package/lib/templates/VoiceControlTemplate.js +20 -0
- package/lib/templates/VoiceControlTemplate.js.map +1 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts +19 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts.map +1 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.js +29 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.js.map +1 -0
- package/lib/templates/android/MessageTemplate.d.ts +16 -0
- package/lib/templates/android/MessageTemplate.d.ts.map +1 -0
- package/lib/templates/android/MessageTemplate.js +11 -0
- package/lib/templates/android/MessageTemplate.js.map +1 -0
- package/lib/templates/android/NavigationTemplate.d.ts +44 -0
- package/lib/templates/android/NavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/NavigationTemplate.js +17 -0
- package/lib/templates/android/NavigationTemplate.js.map +1 -0
- package/lib/templates/android/PaneTemplate.d.ts +20 -0
- package/lib/templates/android/PaneTemplate.d.ts.map +1 -0
- package/lib/templates/android/PaneTemplate.js +17 -0
- package/lib/templates/android/PaneTemplate.js.map +1 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts +78 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts.map +1 -0
- package/lib/templates/android/PlaceListMapTemplate.js +25 -0
- package/lib/templates/android/PlaceListMapTemplate.js.map +1 -0
- package/lib/templates/android/PlaceListNavigationTemplate.d.ts +51 -0
- package/lib/templates/android/PlaceListNavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/PlaceListNavigationTemplate.js +20 -0
- package/lib/templates/android/PlaceListNavigationTemplate.js.map +1 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts +60 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.js +23 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +49 -0
- package/react-native-carplay.podspec +21 -0
- package/src/CarPlay.ts +320 -0
- package/src/index.ts +50 -0
- package/src/interfaces/Action.ts +15 -0
- package/src/interfaces/AlertAction.ts +5 -0
- package/src/interfaces/BarButton.ts +41 -0
- package/src/interfaces/CarColor.ts +1 -0
- package/src/interfaces/GridButton.ts +25 -0
- package/src/interfaces/Header.ts +16 -0
- package/src/interfaces/ListItem.ts +61 -0
- package/src/interfaces/ListItemUpdate.ts +14 -0
- package/src/interfaces/ListSection.ts +21 -0
- package/src/interfaces/Maneuver.ts +30 -0
- package/src/interfaces/MapButton.ts +27 -0
- package/src/interfaces/NavigationAlert.ts +46 -0
- package/src/interfaces/NavigationInfo.ts +19 -0
- package/src/interfaces/NavigationStep.ts +17 -0
- package/src/interfaces/Pane.ts +29 -0
- package/src/interfaces/PauseReason.ts +7 -0
- package/src/interfaces/Place.ts +12 -0
- package/src/interfaces/TextConfiguration.ts +5 -0
- package/src/interfaces/TimeRemainingColor.ts +1 -0
- package/src/interfaces/TravelEstimates.ts +39 -0
- package/src/interfaces/VoiceControlState.ts +8 -0
- package/src/navigation/NavigationSession.ts +57 -0
- package/src/navigation/Trip.ts +36 -0
- package/src/templates/ActionSheetTemplate.ts +21 -0
- package/src/templates/AlertTemplate.ts +20 -0
- package/src/templates/ContactTemplate.ts +45 -0
- package/src/templates/GridTemplate.ts +45 -0
- package/src/templates/InformationTemplate.ts +42 -0
- package/src/templates/ListTemplate.ts +150 -0
- package/src/templates/MapTemplate.ts +231 -0
- package/src/templates/NowPlayingTemplate.ts +38 -0
- package/src/templates/PointOfInterestTemplate.ts +42 -0
- package/src/templates/SearchTemplate.ts +70 -0
- package/src/templates/TabBarTemplate.ts +56 -0
- package/src/templates/Template.ts +165 -0
- package/src/templates/VoiceControlTemplate.ts +25 -0
- package/src/templates/android/AndroidNavigationBaseTemplate.ts +46 -0
- package/src/templates/android/MessageTemplate.ts +19 -0
- package/src/templates/android/NavigationTemplate.ts +50 -0
- package/src/templates/android/PaneTemplate.ts +26 -0
- package/src/templates/android/PlaceListMapTemplate.ts +94 -0
- package/src/templates/android/PlaceListNavigationTemplate.ts +57 -0
- package/src/templates/android/RoutePreviewNavigationTemplate.ts +66 -0
package/ios/RNCarPlay.m
ADDED
|
@@ -0,0 +1,1839 @@
|
|
|
1
|
+
#import "RNCarPlay.h"
|
|
2
|
+
#import <React/RCTConvert.h>
|
|
3
|
+
#import <React/RCTRootView.h>
|
|
4
|
+
|
|
5
|
+
@implementation RNCarPlay
|
|
6
|
+
{
|
|
7
|
+
bool hasListeners;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@synthesize interfaceController;
|
|
11
|
+
@synthesize window;
|
|
12
|
+
@synthesize searchResultBlock;
|
|
13
|
+
@synthesize selectedResultBlock;
|
|
14
|
+
@synthesize isNowPlayingActive;
|
|
15
|
+
|
|
16
|
+
-(void)startObserving {
|
|
17
|
+
hasListeners = YES;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
-(void)stopObserving {
|
|
21
|
+
hasListeners = NO;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
+ (NSDictionary *) getConnectedWindowInformation: (CPWindow *) window {
|
|
25
|
+
return @{
|
|
26
|
+
@"width": @(window.bounds.size.width),
|
|
27
|
+
@"height": @(window.bounds.size.height),
|
|
28
|
+
@"scale": @(window.screen.scale)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
+ (void) connectWithInterfaceController:(CPInterfaceController*)interfaceController window:(CPWindow*)window scene:(CPTemplateApplicationScene*)scene {
|
|
33
|
+
RNCPStore * store = [RNCPStore sharedManager];
|
|
34
|
+
store.interfaceController = interfaceController;
|
|
35
|
+
store.window = window;
|
|
36
|
+
store.scene = scene;
|
|
37
|
+
[store setConnected:true];
|
|
38
|
+
RNCarPlay *cp = [RNCarPlay allocWithZone:nil];
|
|
39
|
+
if (cp.bridge) {
|
|
40
|
+
[cp sendEventWithName:@"didConnect" body:[self getConnectedWindowInformation:window]];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
+ (void) disconnect {
|
|
45
|
+
RNCarPlay *cp = [RNCarPlay allocWithZone:nil];
|
|
46
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
47
|
+
[store setConnected:false];
|
|
48
|
+
[[store.window subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
49
|
+
|
|
50
|
+
if (cp.bridge) {
|
|
51
|
+
[cp sendEventWithName:@"didDisconnect" body:@{}];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
RCT_EXPORT_MODULE();
|
|
56
|
+
|
|
57
|
+
+ (id)allocWithZone:(NSZone *)zone {
|
|
58
|
+
static RNCarPlay *sharedInstance = nil;
|
|
59
|
+
static dispatch_once_t onceToken;
|
|
60
|
+
dispatch_once(&onceToken, ^{
|
|
61
|
+
sharedInstance = [super allocWithZone:zone];
|
|
62
|
+
});
|
|
63
|
+
return sharedInstance;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (NSArray<NSString *> *)supportedEvents
|
|
67
|
+
{
|
|
68
|
+
return @[
|
|
69
|
+
@"didConnect",
|
|
70
|
+
@"didDisconnect",
|
|
71
|
+
// interface
|
|
72
|
+
@"barButtonPressed",
|
|
73
|
+
@"backButtonPressed",
|
|
74
|
+
@"didAppear",
|
|
75
|
+
@"didDisappear",
|
|
76
|
+
@"willAppear",
|
|
77
|
+
@"willDisappear",
|
|
78
|
+
@"buttonPressed",
|
|
79
|
+
// grid
|
|
80
|
+
@"gridButtonPressed",
|
|
81
|
+
// information
|
|
82
|
+
@"actionButtonPressed",
|
|
83
|
+
// list
|
|
84
|
+
@"didSelectListItem",
|
|
85
|
+
// search
|
|
86
|
+
@"updatedSearchText",
|
|
87
|
+
@"searchButtonPressed",
|
|
88
|
+
@"selectedResult",
|
|
89
|
+
// tabbar
|
|
90
|
+
@"didSelectTemplate",
|
|
91
|
+
// nowplaying
|
|
92
|
+
@"upNextButtonPressed",
|
|
93
|
+
@"albumArtistButtonPressed",
|
|
94
|
+
// poi
|
|
95
|
+
@"didSelectPointOfInterest",
|
|
96
|
+
// map
|
|
97
|
+
@"mapButtonPressed",
|
|
98
|
+
@"didUpdatePanGestureWithTranslation",
|
|
99
|
+
@"didEndPanGestureWithVelocity",
|
|
100
|
+
@"panBeganWithDirection",
|
|
101
|
+
@"panEndedWithDirection",
|
|
102
|
+
@"panWithDirection",
|
|
103
|
+
@"didBeginPanGesture",
|
|
104
|
+
@"didDismissPanningInterface",
|
|
105
|
+
@"willDismissPanningInterface",
|
|
106
|
+
@"didShowPanningInterface",
|
|
107
|
+
@"didDismissNavigationAlert",
|
|
108
|
+
@"willDismissNavigationAlert",
|
|
109
|
+
@"didShowNavigationAlert",
|
|
110
|
+
@"willShowNavigationAlert",
|
|
111
|
+
@"didCancelNavigation",
|
|
112
|
+
@"alertActionPressed",
|
|
113
|
+
@"selectedPreviewForTrip",
|
|
114
|
+
@"startedTrip",
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
- (dispatch_queue_t)methodQueue
|
|
119
|
+
{
|
|
120
|
+
return dispatch_get_main_queue();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
-(UIImage *)imageWithTint:(UIImage *)image andTintColor:(UIColor *)tintColor {
|
|
125
|
+
UIImage *imageNew = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
126
|
+
UIImageView *imageView = [[UIImageView alloc] initWithImage:imageNew];
|
|
127
|
+
imageView.tintColor = tintColor;
|
|
128
|
+
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);
|
|
129
|
+
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
|
|
130
|
+
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
131
|
+
UIGraphicsEndImageContext();
|
|
132
|
+
return tintedImage;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
-(UIImage*)dynamicImageWithNormalImage:(UIImage*)normalImage darkImage:(UIImage*)darkImage {
|
|
136
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
137
|
+
if (normalImage == nil || darkImage == nil) {
|
|
138
|
+
return normalImage ? : darkImage;
|
|
139
|
+
}
|
|
140
|
+
if (@available(iOS 14.0, *)) {
|
|
141
|
+
UIImageAsset* imageAsset = darkImage.imageAsset;
|
|
142
|
+
|
|
143
|
+
// darkImage
|
|
144
|
+
UITraitCollection* darkImageTraitCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:
|
|
145
|
+
@[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
|
|
146
|
+
[UITraitCollection traitCollectionWithDisplayScale:normalImage.scale]]];
|
|
147
|
+
[imageAsset registerImage:normalImage withTraitCollection:darkImageTraitCollection];
|
|
148
|
+
|
|
149
|
+
return [imageAsset imageWithTraitCollection: store.interfaceController.carTraitCollection];
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
return normalImage;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
- (UIImage *)imageWithSize:(UIImage *)image convertToSize:(CGSize)size {
|
|
157
|
+
UIGraphicsImageRendererFormat *renderFormat = [UIGraphicsImageRendererFormat defaultFormat];
|
|
158
|
+
renderFormat.opaque = NO;
|
|
159
|
+
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:renderFormat];
|
|
160
|
+
|
|
161
|
+
UIImage *resizedImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
|
|
162
|
+
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
|
163
|
+
}];
|
|
164
|
+
return resizedImage;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
- (void)updateItemImageWithURL:(CPListItem *)item imgUrl:(NSString *)imgUrlString {
|
|
168
|
+
NSURL *imgUrl = [NSURL URLWithString:imgUrlString];
|
|
169
|
+
|
|
170
|
+
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:imgUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
|
171
|
+
if (data) {
|
|
172
|
+
UIImage *image = [UIImage imageWithData:data];
|
|
173
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
174
|
+
[item setImage:image];
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
NSLog(@"Failed to load image from URL: %@", imgUrl);
|
|
178
|
+
}
|
|
179
|
+
}];
|
|
180
|
+
[task resume];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
RCT_EXPORT_METHOD(checkForConnection) {
|
|
184
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
185
|
+
if ([store isConnected] && hasListeners) {
|
|
186
|
+
[self sendEventWithName:@"didConnect" body:[RNCarPlay getConnectedWindowInformation: store.window]];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
RCT_EXPORT_METHOD(openUrl:(NSString *)url) {
|
|
191
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
192
|
+
CPTemplateApplicationScene *templateApplicationScene = store.scene;
|
|
193
|
+
NSURL *URL = [NSURL URLWithString:url];
|
|
194
|
+
[templateApplicationScene openURL:URL options:NULL completionHandler:^(BOOL success) {
|
|
195
|
+
if (success) {
|
|
196
|
+
NSLog(@"Opened url %@", url);
|
|
197
|
+
}
|
|
198
|
+
}];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
RCT_EXPORT_METHOD(createTemplate:(NSString *)templateId config:(NSDictionary*)config callback:(id)callback)
|
|
203
|
+
{
|
|
204
|
+
// Get the shared instance of the RNCPStore class
|
|
205
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
206
|
+
|
|
207
|
+
// Extract values from the 'config' dictionary
|
|
208
|
+
NSString *type = [RCTConvert NSString:config[@"type"]];
|
|
209
|
+
NSString *title = [RCTConvert NSString:config[@"title"]];
|
|
210
|
+
NSArray *leadingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"leadingNavigationBarButtons"]] templateId:templateId];
|
|
211
|
+
NSArray *trailingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"trailingNavigationBarButtons"]] templateId:templateId];
|
|
212
|
+
|
|
213
|
+
// Create a new CPTemplate object
|
|
214
|
+
CPTemplate *carPlayTemplate = [[CPTemplate alloc] init];
|
|
215
|
+
|
|
216
|
+
if ([type isEqualToString:@"search"]) {
|
|
217
|
+
CPSearchTemplate *searchTemplate = [[CPSearchTemplate alloc] init];
|
|
218
|
+
searchTemplate.delegate = self;
|
|
219
|
+
carPlayTemplate = searchTemplate;
|
|
220
|
+
}
|
|
221
|
+
else if ([type isEqualToString:@"grid"]) {
|
|
222
|
+
NSArray *buttons = [self parseGridButtons:[RCTConvert NSArray:config[@"buttons"]] templateId:templateId];
|
|
223
|
+
CPGridTemplate *gridTemplate = [[CPGridTemplate alloc] initWithTitle:title gridButtons:buttons];
|
|
224
|
+
[gridTemplate setLeadingNavigationBarButtons:leadingNavigationBarButtons];
|
|
225
|
+
[gridTemplate setTrailingNavigationBarButtons:trailingNavigationBarButtons];
|
|
226
|
+
carPlayTemplate = gridTemplate;
|
|
227
|
+
}
|
|
228
|
+
else if ([type isEqualToString:@"list"]) {
|
|
229
|
+
NSArray *sections = [self parseSections:[RCTConvert NSArray:config[@"sections"]]];
|
|
230
|
+
CPListTemplate *listTemplate;
|
|
231
|
+
if (@available(iOS 15.0, *)) {
|
|
232
|
+
if ([config objectForKey:@"assistant"]) {
|
|
233
|
+
NSDictionary *assistant = [config objectForKey:@"assistant"];
|
|
234
|
+
BOOL _enabled = [assistant valueForKey:@"enabled"];
|
|
235
|
+
if (_enabled) {
|
|
236
|
+
CPAssistantCellConfiguration *conf = [[CPAssistantCellConfiguration alloc] initWithPosition:[RCTConvert CPAssistantCellPosition:[config valueForKey:@"position"]] visibility:[RCTConvert CPAssistantCellVisibility:[config valueForKey:@"visibility"]] assistantAction:[RCTConvert CPAssistantCellActionType:[config valueForKey:@"visibility"]]];
|
|
237
|
+
listTemplate = [[CPListTemplate alloc] initWithTitle:title sections:sections assistantCellConfiguration:conf];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (listTemplate == nil) {
|
|
242
|
+
// Fallback on earlier versions
|
|
243
|
+
listTemplate = [[CPListTemplate alloc] initWithTitle:title sections:sections];
|
|
244
|
+
}
|
|
245
|
+
[listTemplate setLeadingNavigationBarButtons:leadingNavigationBarButtons];
|
|
246
|
+
[listTemplate setTrailingNavigationBarButtons:trailingNavigationBarButtons];
|
|
247
|
+
if (![RCTConvert BOOL:config[@"backButtonHidden"]]) {
|
|
248
|
+
if (@available(iOS 14.0, *)) {
|
|
249
|
+
CPBarButton *backButton = [[CPBarButton alloc] initWithTitle:@" Back" handler:^(CPBarButton * _Nonnull barButton) {
|
|
250
|
+
if (hasListeners) {
|
|
251
|
+
[self sendEventWithName:@"backButtonPressed" body:@{@"templateId":templateId}];
|
|
252
|
+
}
|
|
253
|
+
[self popTemplate:false];
|
|
254
|
+
}];
|
|
255
|
+
[listTemplate setBackButton:backButton];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (config[@"emptyViewTitleVariants"]) {
|
|
259
|
+
if (@available(iOS 14.0, *)) {
|
|
260
|
+
listTemplate.emptyViewTitleVariants = [RCTConvert NSArray:config[@"emptyViewTitleVariants"]];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (config[@"emptyViewSubtitleVariants"]) {
|
|
264
|
+
if (@available(iOS 14.0, *)) {
|
|
265
|
+
listTemplate.emptyViewSubtitleVariants = [RCTConvert NSArray:config[@"emptyViewSubtitleVariants"]];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
listTemplate.delegate = self;
|
|
269
|
+
carPlayTemplate = listTemplate;
|
|
270
|
+
}
|
|
271
|
+
else if ([type isEqualToString:@"map"]) {
|
|
272
|
+
CPMapTemplate *mapTemplate = [[CPMapTemplate alloc] init];
|
|
273
|
+
|
|
274
|
+
[self applyConfigForMapTemplate:mapTemplate templateId:templateId config:config];
|
|
275
|
+
[mapTemplate setLeadingNavigationBarButtons:leadingNavigationBarButtons];
|
|
276
|
+
[mapTemplate setTrailingNavigationBarButtons:trailingNavigationBarButtons];
|
|
277
|
+
[mapTemplate setUserInfo:@{ @"templateId": templateId }];
|
|
278
|
+
mapTemplate.mapDelegate = self;
|
|
279
|
+
|
|
280
|
+
carPlayTemplate = mapTemplate;
|
|
281
|
+
} else if ([type isEqualToString:@"voicecontrol"]) {
|
|
282
|
+
CPVoiceControlTemplate *voiceTemplate = [[CPVoiceControlTemplate alloc] initWithVoiceControlStates: [self parseVoiceControlStates:config[@"voiceControlStates"]]];
|
|
283
|
+
carPlayTemplate = voiceTemplate;
|
|
284
|
+
} else if ([type isEqualToString:@"nowplaying"]) {
|
|
285
|
+
CPNowPlayingTemplate *nowPlayingTemplate = [CPNowPlayingTemplate sharedTemplate];
|
|
286
|
+
[nowPlayingTemplate setAlbumArtistButtonEnabled:[RCTConvert BOOL:config[@"albumArtistButtonEnabled"]]];
|
|
287
|
+
[nowPlayingTemplate setUpNextTitle:[RCTConvert NSString:config[@"upNextButtonTitle"]]];
|
|
288
|
+
[nowPlayingTemplate setUpNextButtonEnabled:[RCTConvert BOOL:config[@"upNextButtonEnabled"]]];
|
|
289
|
+
NSMutableArray<CPNowPlayingButton *> *buttons = [NSMutableArray new];
|
|
290
|
+
NSArray<NSDictionary*> *_buttons = [RCTConvert NSDictionaryArray:config[@"buttons"]];
|
|
291
|
+
|
|
292
|
+
NSDictionary *buttonTypeMapping = @{
|
|
293
|
+
@"shuffle": CPNowPlayingShuffleButton.class,
|
|
294
|
+
@"add-to-library": CPNowPlayingAddToLibraryButton.class,
|
|
295
|
+
@"more": CPNowPlayingMoreButton.class,
|
|
296
|
+
@"playback": CPNowPlayingPlaybackRateButton.class,
|
|
297
|
+
@"repeat": CPNowPlayingRepeatButton.class,
|
|
298
|
+
@"image": CPNowPlayingImageButton.class
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
for (NSDictionary *_button in _buttons) {
|
|
302
|
+
NSString *buttonType = [RCTConvert NSString:_button[@"type"]];
|
|
303
|
+
NSDictionary *body = @{@"templateId":templateId, @"id": _button[@"id"] };
|
|
304
|
+
Class buttonClass = buttonTypeMapping[buttonType];
|
|
305
|
+
if (buttonClass) {
|
|
306
|
+
CPNowPlayingButton *button = [[buttonClass alloc] initWithHandler:^(__kindof CPNowPlayingButton * _Nonnull) {
|
|
307
|
+
if (self->hasListeners) {
|
|
308
|
+
[self sendEventWithName:@"buttonPressed" body:body];
|
|
309
|
+
}
|
|
310
|
+
}];
|
|
311
|
+
[buttons addObject:button];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
[nowPlayingTemplate updateNowPlayingButtons:buttons];
|
|
315
|
+
carPlayTemplate = nowPlayingTemplate;
|
|
316
|
+
} else if ([type isEqualToString:@"tabbar"]) {
|
|
317
|
+
CPTabBarTemplate *tabBarTemplate = [[CPTabBarTemplate alloc] initWithTemplates:[self parseTemplatesFrom:config]];
|
|
318
|
+
tabBarTemplate.delegate = self;
|
|
319
|
+
carPlayTemplate = tabBarTemplate;
|
|
320
|
+
} else if ([type isEqualToString:@"contact"]) {
|
|
321
|
+
NSString *nm = [RCTConvert NSString:config[@"name"]];
|
|
322
|
+
UIImage *img = [RCTConvert UIImage:config[@"image"]];
|
|
323
|
+
CPContact *contact = [[CPContact alloc] initWithName:nm image:img];
|
|
324
|
+
[contact setSubtitle:config[@"subtitle"]];
|
|
325
|
+
[contact setActions:[self parseButtons:config[@"actions"] templateId:templateId]];
|
|
326
|
+
CPContactTemplate *contactTemplate = [[CPContactTemplate alloc] initWithContact:contact];
|
|
327
|
+
carPlayTemplate = contactTemplate;
|
|
328
|
+
} else if ([type isEqualToString:@"actionsheet"]) {
|
|
329
|
+
NSString *title = [RCTConvert NSString:config[@"title"]];
|
|
330
|
+
NSString *message = [RCTConvert NSString:config[@"message"]];
|
|
331
|
+
NSMutableArray<CPAlertAction *> *actions = [NSMutableArray new];
|
|
332
|
+
NSArray<NSDictionary*> *_actions = [RCTConvert NSDictionaryArray:config[@"actions"]];
|
|
333
|
+
for (NSDictionary *_action in _actions) {
|
|
334
|
+
CPAlertAction *action = [[CPAlertAction alloc] initWithTitle:[RCTConvert NSString:_action[@"title"]] style:[RCTConvert CPAlertActionStyle:_action[@"style"]] handler:^(CPAlertAction *a) {
|
|
335
|
+
if (self->hasListeners) {
|
|
336
|
+
[self sendEventWithName:@"actionButtonPressed" body:@{@"templateId":templateId, @"id": _action[@"id"] }];
|
|
337
|
+
}
|
|
338
|
+
}];
|
|
339
|
+
[actions addObject:action];
|
|
340
|
+
}
|
|
341
|
+
CPActionSheetTemplate *actionSheetTemplate = [[CPActionSheetTemplate alloc] initWithTitle:title message:message actions:actions];
|
|
342
|
+
carPlayTemplate = actionSheetTemplate;
|
|
343
|
+
} else if ([type isEqualToString:@"alert"]) {
|
|
344
|
+
NSMutableArray<CPAlertAction *> *actions = [NSMutableArray new];
|
|
345
|
+
NSArray<NSDictionary*> *_actions = [RCTConvert NSDictionaryArray:config[@"actions"]];
|
|
346
|
+
for (NSDictionary *_action in _actions) {
|
|
347
|
+
CPAlertAction *action = [[CPAlertAction alloc] initWithTitle:[RCTConvert NSString:_action[@"title"]] style:[RCTConvert CPAlertActionStyle:_action[@"style"]] handler:^(CPAlertAction *a) {
|
|
348
|
+
if (self->hasListeners) {
|
|
349
|
+
[self sendEventWithName:@"actionButtonPressed" body:@{@"templateId":templateId, @"id": _action[@"id"] }];
|
|
350
|
+
}
|
|
351
|
+
}];
|
|
352
|
+
[actions addObject:action];
|
|
353
|
+
}
|
|
354
|
+
NSArray<NSString*>* titleVariants = [RCTConvert NSArray:config[@"titleVariants"]];
|
|
355
|
+
CPAlertTemplate *alertTemplate = [[CPAlertTemplate alloc] initWithTitleVariants:titleVariants actions:actions];
|
|
356
|
+
carPlayTemplate = alertTemplate;
|
|
357
|
+
} else if ([type isEqualToString:@"poi"]) {
|
|
358
|
+
// NSString *title = [RCTConvert NSString:config[@"title"]];
|
|
359
|
+
// NSMutableArray<__kindof CPPointOfInterest *> * items = [NSMutableArray new];
|
|
360
|
+
// NSUInteger selectedIndex = 0;
|
|
361
|
+
|
|
362
|
+
// NSArray<NSDictionary*> *_items = [RCTConvert NSDictionaryArray:config[@"items"]];
|
|
363
|
+
// for (NSDictionary *_item in _items) {
|
|
364
|
+
// CPPointOfInterest *poi = [RCTConvert CPPointOfInterest:_item];
|
|
365
|
+
// [poi setUserInfo:_item];
|
|
366
|
+
// [items addObject:poi];
|
|
367
|
+
// }
|
|
368
|
+
|
|
369
|
+
// CPPointOfInterestTemplate *poiTemplate = [[CPPointOfInterestTemplate alloc] initWithTitle:title pointsOfInterest:items selectedIndex:selectedIndex];
|
|
370
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
371
|
+
|
|
372
|
+
CPPointOfInterestTemplate *poiTemplate = [self createCarPlayPOISCreen:store.interfaceController responseList:config[@"items"] templateId:templateId];
|
|
373
|
+
|
|
374
|
+
poiTemplate.pointOfInterestDelegate = self;
|
|
375
|
+
carPlayTemplate = poiTemplate;
|
|
376
|
+
} else if ([type isEqualToString:@"information"]) {
|
|
377
|
+
NSString *title = [RCTConvert NSString:config[@"title"]];
|
|
378
|
+
CPInformationTemplateLayout layout = [RCTConvert BOOL:config[@"leading"]] ? CPInformationTemplateLayoutLeading : CPInformationTemplateLayoutTwoColumn;
|
|
379
|
+
NSMutableArray<__kindof CPInformationItem *> * items = [NSMutableArray new];
|
|
380
|
+
NSMutableArray<__kindof CPTextButton *> * actions = [NSMutableArray new];
|
|
381
|
+
|
|
382
|
+
NSArray<NSDictionary*> *_items = [RCTConvert NSDictionaryArray:config[@"items"]];
|
|
383
|
+
for (NSDictionary *_item in _items) {
|
|
384
|
+
[items addObject:[[CPInformationItem alloc] initWithTitle:_item[@"title"] detail:_item[@"detail"]]];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
NSArray<NSDictionary*> *_actions = [RCTConvert NSDictionaryArray:config[@"actions"]];
|
|
388
|
+
for (NSDictionary *_action in _actions) {
|
|
389
|
+
CPTextButton *action = [[CPTextButton alloc] initWithTitle:_action[@"title"] textStyle:CPTextButtonStyleNormal handler:^(__kindof CPTextButton * _Nonnull contactButton) {
|
|
390
|
+
if (self->hasListeners) {
|
|
391
|
+
[self sendEventWithName:@"actionButtonPressed" body:@{@"templateId":templateId, @"id": _action[@"id"] }];
|
|
392
|
+
}
|
|
393
|
+
}];
|
|
394
|
+
[actions addObject:action];
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
CPInformationTemplate *informationTemplate = [[CPInformationTemplate alloc] initWithTitle:title layout:layout items:items actions:actions];
|
|
398
|
+
carPlayTemplate = informationTemplate;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (config[@"tabSystemItem"]) {
|
|
402
|
+
carPlayTemplate.tabSystemItem = [RCTConvert NSInteger:config[@"tabSystemItem"]];
|
|
403
|
+
}
|
|
404
|
+
if (config[@"tabSystemImageName"]) {
|
|
405
|
+
carPlayTemplate.tabImage = [UIImage systemImageNamed:[RCTConvert NSString:config[@"tabSystemImageName"]]];
|
|
406
|
+
}
|
|
407
|
+
if (config[@"tabImage"]) {
|
|
408
|
+
carPlayTemplate.tabImage = [RCTConvert UIImage:config[@"tabImage"]];
|
|
409
|
+
}
|
|
410
|
+
if (config[@"tabTitle"]) {
|
|
411
|
+
carPlayTemplate.tabTitle = [RCTConvert NSString:config[@"tabTitle"]];
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
[carPlayTemplate setUserInfo:@{ @"templateId": templateId }];
|
|
415
|
+
[store setTemplate:templateId template:carPlayTemplate];
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
RCT_EXPORT_METHOD(createTrip:(NSString*)tripId config:(NSDictionary*)config) {
|
|
419
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
420
|
+
CPTrip *trip = [self parseTrip:config];
|
|
421
|
+
NSMutableDictionary *userInfo = trip.userInfo;
|
|
422
|
+
if (!userInfo) {
|
|
423
|
+
userInfo = [[NSMutableDictionary alloc] init];
|
|
424
|
+
trip.userInfo = userInfo;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
[userInfo setValue:tripId forKey:@"id"];
|
|
428
|
+
[store setTrip:tripId trip:trip];
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
RCT_EXPORT_METHOD(updateTravelEstimatesForTrip:(NSString*)templateId tripId:(NSString*)tripId travelEstimates:(NSDictionary*)travelEstimates timeRemainingColor:(NSUInteger*)timeRemainingColor) {
|
|
432
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
433
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
434
|
+
if (template) {
|
|
435
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
436
|
+
CPTrip *trip = [[RNCPStore sharedManager] findTripById:tripId];
|
|
437
|
+
if (trip) {
|
|
438
|
+
CPTravelEstimates *estimates = [self parseTravelEstimates:travelEstimates];
|
|
439
|
+
[mapTemplate updateTravelEstimates:estimates forTrip:trip withTimeRemainingColor:(CPTimeRemainingColor) timeRemainingColor];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
RCT_REMAP_METHOD(startNavigationSession,
|
|
445
|
+
templateId:(NSString *)templateId
|
|
446
|
+
tripId:(NSString *)tripId
|
|
447
|
+
startNavigationSessionWithResolver:(RCTPromiseResolveBlock)resolve
|
|
448
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
449
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
450
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
451
|
+
if (template) {
|
|
452
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
453
|
+
CPTrip *trip = [[RNCPStore sharedManager] findTripById:tripId];
|
|
454
|
+
if (trip) {
|
|
455
|
+
CPNavigationSession *navigationSession = [mapTemplate startNavigationSessionForTrip:trip];
|
|
456
|
+
[store setNavigationSession:tripId navigationSession:navigationSession];
|
|
457
|
+
resolve(@{ @"tripId": tripId, @"navigationSessionId": tripId });
|
|
458
|
+
}
|
|
459
|
+
} else {
|
|
460
|
+
reject(@"template_not_found", @"Template not found in store", nil);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
RCT_EXPORT_METHOD(updateManeuversNavigationSession:(NSString*)navigationSessionId maneuvers:(NSArray*)maneuvers) {
|
|
465
|
+
CPNavigationSession* navigationSession = [[RNCPStore sharedManager] findNavigationSessionById:navigationSessionId];
|
|
466
|
+
if (navigationSession) {
|
|
467
|
+
NSMutableArray<CPManeuver*>* upcomingManeuvers = [NSMutableArray array];
|
|
468
|
+
for (NSDictionary *maneuver in maneuvers) {
|
|
469
|
+
[upcomingManeuvers addObject:[self parseManeuver:maneuver]];
|
|
470
|
+
}
|
|
471
|
+
[navigationSession setUpcomingManeuvers:upcomingManeuvers];
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
RCT_EXPORT_METHOD(updateTravelEstimatesNavigationSession:(NSString*)navigationSessionId maneuverIndex:(NSUInteger)maneuverIndex travelEstimates:(NSDictionary*)travelEstimates) {
|
|
476
|
+
CPNavigationSession* navigationSession = [[RNCPStore sharedManager] findNavigationSessionById:navigationSessionId];
|
|
477
|
+
if (navigationSession) {
|
|
478
|
+
CPManeuver *maneuver = [[navigationSession upcomingManeuvers] objectAtIndex:maneuverIndex];
|
|
479
|
+
if (maneuver) {
|
|
480
|
+
[navigationSession updateTravelEstimates:[self parseTravelEstimates:travelEstimates] forManeuver:maneuver];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
RCT_EXPORT_METHOD(pauseNavigationSession:(NSString*)navigationSessionId reason:(NSUInteger*)reason description:(NSString*)description) {
|
|
486
|
+
CPNavigationSession* navigationSession = [[RNCPStore sharedManager] findNavigationSessionById:navigationSessionId];
|
|
487
|
+
if (navigationSession) {
|
|
488
|
+
[navigationSession pauseTripForReason:(CPTripPauseReason) reason description:description];
|
|
489
|
+
} else {
|
|
490
|
+
NSLog(@"Could not find session");
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
RCT_EXPORT_METHOD(cancelNavigationSession:(NSString*)navigationSessionId) {
|
|
495
|
+
CPNavigationSession* navigationSession = [[RNCPStore sharedManager] findNavigationSessionById:navigationSessionId];
|
|
496
|
+
if (navigationSession) {
|
|
497
|
+
[navigationSession cancelTrip];
|
|
498
|
+
} else {
|
|
499
|
+
NSLog(@"Could not cancel. No session found.");
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
RCT_EXPORT_METHOD(finishNavigationSession:(NSString*)navigationSessionId) {
|
|
504
|
+
CPNavigationSession* navigationSession = [[RNCPStore sharedManager] findNavigationSessionById:navigationSessionId];
|
|
505
|
+
if (navigationSession) {
|
|
506
|
+
[navigationSession finishTrip];
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
RCT_EXPORT_METHOD(setRootTemplate:(NSString *)templateId animated:(BOOL)animated) {
|
|
511
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
512
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
513
|
+
|
|
514
|
+
store.interfaceController.delegate = self;
|
|
515
|
+
|
|
516
|
+
if (template) {
|
|
517
|
+
[store.interfaceController setRootTemplate:template animated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
518
|
+
NSLog(@"error at setRootTemplate%@", err);
|
|
519
|
+
// noop
|
|
520
|
+
}];
|
|
521
|
+
} else {
|
|
522
|
+
NSLog(@"Failed to find template %@", template);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
RCT_EXPORT_METHOD(pushTemplate:(NSString *)templateId animated:(BOOL)animated) {
|
|
527
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
528
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
529
|
+
if (template) {
|
|
530
|
+
[store.interfaceController pushTemplate:template animated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
531
|
+
NSLog(@"error at pushTemplate %@", err);
|
|
532
|
+
// noop
|
|
533
|
+
}];
|
|
534
|
+
} else {
|
|
535
|
+
NSLog(@"Failed to find template %@", template);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
RCT_EXPORT_METHOD(popToTemplate:(NSString *)templateId animated:(BOOL)animated) {
|
|
540
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
541
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
542
|
+
if (template) {
|
|
543
|
+
[store.interfaceController popToTemplate:template animated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
544
|
+
NSLog(@"error at popToTemplate %@", err);
|
|
545
|
+
// noop
|
|
546
|
+
}];
|
|
547
|
+
} else {
|
|
548
|
+
NSLog(@"Failed to find template %@", template);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
RCT_EXPORT_METHOD(popToRootTemplate:(BOOL)animated) {
|
|
553
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
554
|
+
[store.interfaceController popToRootTemplateAnimated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
555
|
+
NSLog(@"error at popToRootTemplate %@", err);
|
|
556
|
+
// noop
|
|
557
|
+
}];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
RCT_EXPORT_METHOD(popTemplate:(BOOL)animated) {
|
|
561
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
562
|
+
[store.interfaceController popTemplateAnimated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
563
|
+
NSLog(@"error at popTemplate %@", err);
|
|
564
|
+
// noop
|
|
565
|
+
}];
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
RCT_EXPORT_METHOD(presentTemplate:(NSString *)templateId animated:(BOOL)animated) {
|
|
569
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
570
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
571
|
+
if (template) {
|
|
572
|
+
[store.interfaceController presentTemplate:template animated:animated completion:^(BOOL done, NSError * _Nullable err) {
|
|
573
|
+
NSLog(@"error at presentTemplate %@", err);
|
|
574
|
+
// noop
|
|
575
|
+
}];
|
|
576
|
+
} else {
|
|
577
|
+
NSLog(@"Failed to find template %@", template);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
RCT_EXPORT_METHOD(dismissTemplate:(BOOL)animated) {
|
|
582
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
583
|
+
[store.interfaceController dismissTemplateAnimated:animated];
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
RCT_EXPORT_METHOD(updateListTemplate:(NSString*)templateId config:(NSDictionary*)config) {
|
|
587
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
588
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
589
|
+
if (template && [template isKindOfClass:[CPListTemplate class]]) {
|
|
590
|
+
CPListTemplate *listTemplate = (CPListTemplate *)template;
|
|
591
|
+
if (config[@"leadingNavigationBarButtons"]) {
|
|
592
|
+
NSArray *leadingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"leadingNavigationBarButtons"]] templateId:templateId];
|
|
593
|
+
[listTemplate setLeadingNavigationBarButtons:leadingNavigationBarButtons];
|
|
594
|
+
}
|
|
595
|
+
if (config[@"trailingNavigationBarButtons"]) {
|
|
596
|
+
NSArray *trailingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"trailingNavigationBarButtons"]] templateId:templateId];
|
|
597
|
+
[listTemplate setTrailingNavigationBarButtons:trailingNavigationBarButtons];
|
|
598
|
+
}
|
|
599
|
+
if (config[@"emptyViewTitleVariants"]) {
|
|
600
|
+
listTemplate.emptyViewTitleVariants = [RCTConvert NSArray:config[@"emptyViewTitleVariants"]];
|
|
601
|
+
}
|
|
602
|
+
if (config[@"emptyViewSubtitleVariants"]) {
|
|
603
|
+
NSLog(@"%@", [RCTConvert NSArray:config[@"emptyViewSubtitleVariants"]]);
|
|
604
|
+
listTemplate.emptyViewSubtitleVariants = [RCTConvert NSArray:config[@"emptyViewSubtitleVariants"]];
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
RCT_EXPORT_METHOD(updateTabBarTemplates:(NSString *)templateId templates:(NSDictionary*)config) {
|
|
610
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
611
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
612
|
+
if (template) {
|
|
613
|
+
CPTabBarTemplate *tabBarTemplate = (CPTabBarTemplate*) template;
|
|
614
|
+
[tabBarTemplate updateTemplates:[self parseTemplatesFrom:config]];
|
|
615
|
+
} else {
|
|
616
|
+
NSLog(@"Failed to find template %@", template);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
RCT_EXPORT_METHOD(updateListTemplateSections:(NSString *)templateId sections:(NSArray*)sections) {
|
|
622
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
623
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
624
|
+
if (template) {
|
|
625
|
+
CPListTemplate *listTemplate = (CPListTemplate*) template;
|
|
626
|
+
[listTemplate updateSections:[self parseSections:sections]];
|
|
627
|
+
} else {
|
|
628
|
+
NSLog(@"Failed to find template %@", template);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
RCT_EXPORT_METHOD(updateListTemplateItem:(NSString *)templateId config:(NSDictionary*)config) {
|
|
633
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
634
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
635
|
+
if (template) {
|
|
636
|
+
CPListTemplate *listTemplate = (CPListTemplate*) template;
|
|
637
|
+
NSInteger sectionIndex = [RCTConvert NSInteger:config[@"sectionIndex"]];
|
|
638
|
+
if (sectionIndex >= listTemplate.sections.count) {
|
|
639
|
+
NSLog(@"Failed to update item at section %d, sections size is %d", index, listTemplate.sections.count);
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
CPListSection *section = listTemplate.sections[sectionIndex];
|
|
643
|
+
NSInteger index = [RCTConvert NSInteger:config[@"itemIndex"]];
|
|
644
|
+
if (index >= section.items.count) {
|
|
645
|
+
NSLog(@"Failed to update item at index %d, section size is %d", index, section.items.count);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
CPListItem *item = (CPListItem *)section.items[index];
|
|
649
|
+
if (config[@"imgUrl"]) {
|
|
650
|
+
NSString *imgUrlString = [RCTConvert NSString:config[@"imgUrl"]];
|
|
651
|
+
[self updateItemImageWithURL:item imgUrl:imgUrlString];
|
|
652
|
+
}
|
|
653
|
+
if (config[@"image"]) {
|
|
654
|
+
[item setImage:[RCTConvert UIImage:config[@"image"]]];
|
|
655
|
+
}
|
|
656
|
+
if (config[@"text"]) {
|
|
657
|
+
[item setText:[RCTConvert NSString:config[@"text"]]];
|
|
658
|
+
}
|
|
659
|
+
if (config[@"detailText"]) {
|
|
660
|
+
[item setDetailText:[RCTConvert NSString:config[@"detailText"]]];
|
|
661
|
+
}
|
|
662
|
+
if (config[@"isPlaying"]) {
|
|
663
|
+
[item setPlaying:[RCTConvert BOOL:config[@"isPlaying"]]];
|
|
664
|
+
}
|
|
665
|
+
} else {
|
|
666
|
+
NSLog(@"Failed to find template %@", template);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
RCT_EXPORT_METHOD(updateInformationTemplateItems:(NSString *)templateId items:(NSArray*)items) {
|
|
671
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
672
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
673
|
+
if (template) {
|
|
674
|
+
CPInformationTemplate *informationTemplate = (CPInformationTemplate*) template;
|
|
675
|
+
informationTemplate.items = [self parseInformationItems:items];
|
|
676
|
+
} else {
|
|
677
|
+
NSLog(@"Failed to find template %@", template);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
RCT_EXPORT_METHOD(updateInformationTemplateActions:(NSString *)templateId items:(NSArray*)actions) {
|
|
682
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
683
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
684
|
+
if (template) {
|
|
685
|
+
CPInformationTemplate *informationTemplate = (CPInformationTemplate*) template;
|
|
686
|
+
informationTemplate.actions = [self parseInformationActions:actions templateId:templateId];
|
|
687
|
+
} else {
|
|
688
|
+
NSLog(@"Failed to find template %@", template);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
RCT_EXPORT_METHOD(getMaximumListItemCount:(NSString *)templateId
|
|
693
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
694
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
695
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
696
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
697
|
+
if (template) {
|
|
698
|
+
CPListTemplate *listTemplate = (CPListTemplate*) template;
|
|
699
|
+
resolve(@(CPListTemplate.maximumItemCount));
|
|
700
|
+
} else {
|
|
701
|
+
NSLog(@"Failed to find template %@", template);
|
|
702
|
+
reject(@"template_not_found", @"Template not found in store", nil);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
RCT_EXPORT_METHOD(getMaximumListSectionCount:(NSString *)templateId
|
|
707
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
708
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
709
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
710
|
+
CPTemplate *template = [store findTemplateById:templateId];
|
|
711
|
+
if (template) {
|
|
712
|
+
CPListTemplate *listTemplate = (CPListTemplate*) template;
|
|
713
|
+
resolve(@(CPListTemplate.maximumSectionCount));
|
|
714
|
+
} else {
|
|
715
|
+
NSLog(@"Failed to find template %@", template);
|
|
716
|
+
reject(@"template_not_found", @"Template not found in store", nil);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
RCT_EXPORT_METHOD(updateMapTemplateConfig:(NSString *)templateId config:(NSDictionary*)config) {
|
|
721
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
722
|
+
if (template) {
|
|
723
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
724
|
+
[self applyConfigForMapTemplate:mapTemplate templateId:templateId config:config];
|
|
725
|
+
} else {
|
|
726
|
+
NSLog(@"Failed to find template %@", template);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
RCT_EXPORT_METHOD(showPanningInterface:(NSString *)templateId animated:(BOOL)animated) {
|
|
731
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
732
|
+
if (template) {
|
|
733
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
734
|
+
[mapTemplate showPanningInterfaceAnimated:animated];
|
|
735
|
+
} else {
|
|
736
|
+
NSLog(@"Failed to find template %@", template);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
RCT_EXPORT_METHOD(dismissPanningInterface:(NSString *)templateId animated:(BOOL)animated) {
|
|
741
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
742
|
+
if (template) {
|
|
743
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
744
|
+
[mapTemplate dismissPanningInterfaceAnimated:animated];
|
|
745
|
+
} else {
|
|
746
|
+
NSLog(@"Failed to find template %@", template);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
RCT_EXPORT_METHOD(enableNowPlaying:(BOOL)enable) {
|
|
751
|
+
if (enable && !isNowPlayingActive) {
|
|
752
|
+
[CPNowPlayingTemplate.sharedTemplate addObserver:self];
|
|
753
|
+
} else if (!enable && isNowPlayingActive) {
|
|
754
|
+
[CPNowPlayingTemplate.sharedTemplate removeObserver:self];
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
RCT_EXPORT_METHOD(hideTripPreviews:(NSString*)templateId) {
|
|
759
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
760
|
+
if (template) {
|
|
761
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
762
|
+
[mapTemplate hideTripPreviews];
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
RCT_EXPORT_METHOD(showTripPreviews:(NSString*)templateId tripIds:(NSArray*)tripIds tripConfiguration:(NSDictionary*)tripConfiguration) {
|
|
767
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
768
|
+
NSMutableArray *trips = [[NSMutableArray alloc] init];
|
|
769
|
+
|
|
770
|
+
for (NSString *tripId in tripIds) {
|
|
771
|
+
CPTrip *trip = [[RNCPStore sharedManager] findTripById:tripId];
|
|
772
|
+
if (trip) {
|
|
773
|
+
[trips addObject:trip];
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (template) {
|
|
778
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
779
|
+
[mapTemplate showTripPreviews:trips textConfiguration:[self parseTripPreviewTextConfiguration:tripConfiguration]];
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
RCT_EXPORT_METHOD(showRouteChoicesPreviewForTrip:(NSString*)templateId tripId:(NSString*)tripId tripConfiguration:(NSDictionary*)tripConfiguration) {
|
|
784
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
785
|
+
CPTrip *trip = [[RNCPStore sharedManager] findTripById:tripId];
|
|
786
|
+
|
|
787
|
+
if (template) {
|
|
788
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
789
|
+
[mapTemplate showRouteChoicesPreviewForTrip:trip textConfiguration:[self parseTripPreviewTextConfiguration:tripConfiguration]];
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
RCT_EXPORT_METHOD(presentNavigationAlert:(NSString*)templateId json:(NSDictionary*)json animated:(BOOL)animated) {
|
|
794
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
795
|
+
if (template) {
|
|
796
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
797
|
+
[mapTemplate presentNavigationAlert:[self parseNavigationAlert:json templateId:templateId] animated:animated];
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
RCT_EXPORT_METHOD(dismissNavigationAlert:(NSString*)templateId animated:(BOOL)animated) {
|
|
802
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
803
|
+
if (template) {
|
|
804
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
805
|
+
[mapTemplate dismissNavigationAlertAnimated:YES completion:^(BOOL completion) {
|
|
806
|
+
[self sendTemplateEventWithName:template name:@"didDismissNavigationAlert"];
|
|
807
|
+
}];
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
RCT_EXPORT_METHOD(activateVoiceControlState:(NSString*)templateId identifier:(NSString*)identifier) {
|
|
812
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
813
|
+
if (template) {
|
|
814
|
+
CPVoiceControlTemplate *voiceTemplate = (CPVoiceControlTemplate*) template;
|
|
815
|
+
[voiceTemplate activateVoiceControlStateWithIdentifier:identifier];
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
RCT_EXPORT_METHOD(reactToUpdatedSearchText:(NSArray *)items) {
|
|
820
|
+
NSArray *sectionsItems = [self parseListItems:items startIndex:0];
|
|
821
|
+
|
|
822
|
+
if (self.searchResultBlock) {
|
|
823
|
+
self.searchResultBlock(sectionsItems);
|
|
824
|
+
self.searchResultBlock = nil;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
RCT_EXPORT_METHOD(reactToSelectedResult:(BOOL)status) {
|
|
829
|
+
if (self.selectedResultBlock) {
|
|
830
|
+
self.selectedResultBlock();
|
|
831
|
+
self.selectedResultBlock = nil;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
RCT_EXPORT_METHOD(updateMapTemplateMapButtons:(NSString*) templateId mapButtons:(NSArray*) mapButtonConfig) {
|
|
836
|
+
CPTemplate *template = [[RNCPStore sharedManager] findTemplateById:templateId];
|
|
837
|
+
if (template) {
|
|
838
|
+
CPMapTemplate *mapTemplate = (CPMapTemplate*) template;
|
|
839
|
+
NSArray *mapButtons = [RCTConvert NSArray:mapButtonConfig];
|
|
840
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
841
|
+
for (NSDictionary *mapButton in mapButtons) {
|
|
842
|
+
NSString *_id = [mapButton objectForKey:@"id"];
|
|
843
|
+
[result addObject:[RCTConvert CPMapButton:mapButton withHandler:^(CPMapButton * _Nonnull mapButton) {
|
|
844
|
+
[self sendTemplateEventWithName:mapTemplate name:@"mapButtonPressed" json:@{ @"id": _id }];
|
|
845
|
+
}]];
|
|
846
|
+
}
|
|
847
|
+
[mapTemplate setMapButtons:result];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
# pragma parsers
|
|
852
|
+
|
|
853
|
+
- (void) applyConfigForMapTemplate:(CPMapTemplate*)mapTemplate templateId:(NSString*)templateId config:(NSDictionary*)config {
|
|
854
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
855
|
+
|
|
856
|
+
if ([config objectForKey:@"guidanceBackgroundColor"]) {
|
|
857
|
+
[mapTemplate setGuidanceBackgroundColor:[RCTConvert UIColor:config[@"guidanceBackgroundColor"]]];
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
[mapTemplate setGuidanceBackgroundColor:UIColor.systemGray5Color];
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if ([config objectForKey:@"tripEstimateStyle"]) {
|
|
864
|
+
[mapTemplate setTripEstimateStyle:[RCTConvert CPTripEstimateStyle:config[@"tripEstimateStyle"]]];
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
[mapTemplate setTripEstimateStyle:CPTripEstimateStyleDark];
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if ([config objectForKey:@"leadingNavigationBarButtons"]){
|
|
871
|
+
NSArray *leadingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"leadingNavigationBarButtons"]] templateId:templateId];
|
|
872
|
+
[mapTemplate setLeadingNavigationBarButtons:leadingNavigationBarButtons];
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if ([config objectForKey:@"trailingNavigationBarButtons"]){
|
|
876
|
+
NSArray *trailingNavigationBarButtons = [self parseBarButtons:[RCTConvert NSArray:config[@"trailingNavigationBarButtons"]] templateId:templateId];
|
|
877
|
+
[mapTemplate setTrailingNavigationBarButtons:trailingNavigationBarButtons];
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if ([config objectForKey:@"mapButtons"]) {
|
|
881
|
+
NSArray *mapButtons = [RCTConvert NSArray:config[@"mapButtons"]];
|
|
882
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
883
|
+
for (NSDictionary *mapButton in mapButtons) {
|
|
884
|
+
NSString *_id = [mapButton objectForKey:@"id"];
|
|
885
|
+
[result addObject:[RCTConvert CPMapButton:mapButton withHandler:^(CPMapButton * _Nonnull mapButton) {
|
|
886
|
+
[self sendTemplateEventWithName:mapTemplate name:@"mapButtonPressed" json:@{ @"id": _id }];
|
|
887
|
+
}]];
|
|
888
|
+
}
|
|
889
|
+
[mapTemplate setMapButtons:result];
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
if ([config objectForKey:@"automaticallyHidesNavigationBar"]) {
|
|
893
|
+
[mapTemplate setAutomaticallyHidesNavigationBar:[RCTConvert BOOL:config[@"automaticallyHidesNavigationBar"]]];
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if ([config objectForKey:@"hidesButtonsWithNavigationBar"]) {
|
|
897
|
+
[mapTemplate setHidesButtonsWithNavigationBar:[RCTConvert BOOL:config[@"hidesButtonsWithNavigationBar"]]];
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
if ([config objectForKey:@"render"]) {
|
|
901
|
+
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:templateId initialProperties:@{}];
|
|
902
|
+
[rootView setFrame:store.window.frame];
|
|
903
|
+
[[store.window subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
904
|
+
[store.window addSubview:rootView];
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
- (NSArray<__kindof CPTemplate*>*) parseTemplatesFrom:(NSDictionary*)config {
|
|
909
|
+
RNCPStore *store = [RNCPStore sharedManager];
|
|
910
|
+
NSMutableArray<__kindof CPTemplate*> *templates = [NSMutableArray new];
|
|
911
|
+
NSArray<NSDictionary*> *tpls = [RCTConvert NSDictionaryArray:config[@"templates"]];
|
|
912
|
+
for (NSDictionary *tpl in tpls) {
|
|
913
|
+
CPTemplate *templ = [store findTemplateById:tpl[@"id"]];
|
|
914
|
+
// @todo UITabSystemItem
|
|
915
|
+
[templates addObject:templ];
|
|
916
|
+
}
|
|
917
|
+
return templates;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
- (NSArray<CPButton*>*) parseButtons:(NSArray*)buttons templateId:(NSString *)templateId {
|
|
921
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
922
|
+
for (NSDictionary *button in buttons) {
|
|
923
|
+
CPButton *_button;
|
|
924
|
+
NSString *_id = [button objectForKey:@"id"];
|
|
925
|
+
NSString *type = [button objectForKey:@"type"];
|
|
926
|
+
if ([type isEqualToString:@"call"]) {
|
|
927
|
+
_button = [[CPContactCallButton alloc] initWithHandler:^(__kindof CPButton * _Nonnull contactButton) {
|
|
928
|
+
if (self->hasListeners) {
|
|
929
|
+
[self sendEventWithName:@"buttonPressed" body:@{@"id": _id, @"templateId":templateId}];
|
|
930
|
+
}
|
|
931
|
+
}];
|
|
932
|
+
} else if ([type isEqualToString:@"message"]) {
|
|
933
|
+
_button = [[CPContactMessageButton alloc] initWithPhoneOrEmail:[button objectForKey:@"phoneOrEmail"]];
|
|
934
|
+
} else if ([type isEqualToString:@"directions"]) {
|
|
935
|
+
_button = [[CPContactDirectionsButton alloc] initWithHandler:^(__kindof CPButton * _Nonnull contactButton) {
|
|
936
|
+
if (self->hasListeners) {
|
|
937
|
+
[self sendEventWithName:@"buttonPressed" body:@{@"id": _id, @"templateId":templateId}];
|
|
938
|
+
}
|
|
939
|
+
}];
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
BOOL _disabled = [button objectForKey:@"disabled"];
|
|
943
|
+
[_button setEnabled:!_disabled];
|
|
944
|
+
|
|
945
|
+
NSString *_title = [button objectForKey:@"title"];
|
|
946
|
+
[_button setTitle:_title];
|
|
947
|
+
|
|
948
|
+
[result addObject:_button];
|
|
949
|
+
}
|
|
950
|
+
return result;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
- (NSArray<CPBarButton*>*) parseBarButtons:(NSArray*)barButtons templateId:(NSString *)templateId {
|
|
954
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
955
|
+
for (NSDictionary *barButton in barButtons) {
|
|
956
|
+
CPBarButtonType _type;
|
|
957
|
+
NSString *_id = [barButton objectForKey:@"id"];
|
|
958
|
+
NSString *type = [barButton objectForKey:@"type"];
|
|
959
|
+
if (type && [type isEqualToString:@"image"]) {
|
|
960
|
+
_type = CPBarButtonTypeImage;
|
|
961
|
+
} else {
|
|
962
|
+
_type = CPBarButtonTypeText;
|
|
963
|
+
}
|
|
964
|
+
CPBarButton *_barButton = [[CPBarButton alloc] initWithType:_type handler:^(CPBarButton * _Nonnull barButton) {
|
|
965
|
+
if (self->hasListeners) {
|
|
966
|
+
[self sendEventWithName:@"barButtonPressed" body:@{@"id": _id, @"templateId":templateId}];
|
|
967
|
+
}
|
|
968
|
+
}];
|
|
969
|
+
BOOL _disabled = [barButton objectForKey:@"disabled"];
|
|
970
|
+
[_barButton setEnabled:!_disabled];
|
|
971
|
+
|
|
972
|
+
if (_type == CPBarButtonTypeText) {
|
|
973
|
+
NSString *_title = [barButton objectForKey:@"title"];
|
|
974
|
+
[_barButton setTitle:_title];
|
|
975
|
+
} else if (_type == CPBarButtonTypeImage) {
|
|
976
|
+
UIImage *_image = [RCTConvert UIImage:[barButton objectForKey:@"image"]];
|
|
977
|
+
[_barButton setImage:_image];
|
|
978
|
+
}
|
|
979
|
+
[result addObject:_barButton];
|
|
980
|
+
}
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
- (NSArray<CPListSection*>*)parseSections:(NSArray*)sections {
|
|
985
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
986
|
+
int index = 0;
|
|
987
|
+
for (NSDictionary *section in sections) {
|
|
988
|
+
NSArray *items = [section objectForKey:@"items"];
|
|
989
|
+
NSString *_sectionIndexTitle = [section objectForKey:@"sectionIndexTitle"];
|
|
990
|
+
NSString *_header = [section objectForKey:@"header"];
|
|
991
|
+
NSArray *_items = [self parseListItems:items startIndex:index];
|
|
992
|
+
CPListSection *_section = [[CPListSection alloc] initWithItems:_items header:_header sectionIndexTitle:_sectionIndexTitle];
|
|
993
|
+
[result addObject:_section];
|
|
994
|
+
int count = (int) [items count];
|
|
995
|
+
index = index + count;
|
|
996
|
+
}
|
|
997
|
+
return result;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
- (NSArray<CPListItem*>*)parseListItems:(NSArray*)items startIndex:(int)startIndex {
|
|
1001
|
+
NSMutableArray *_items = [NSMutableArray array];
|
|
1002
|
+
int index = startIndex;
|
|
1003
|
+
for (NSDictionary *item in items) {
|
|
1004
|
+
BOOL _showsDisclosureIndicator = [[item objectForKey:@"showsDisclosureIndicator"] isEqualToNumber:[NSNumber numberWithInt:1]];
|
|
1005
|
+
NSString *_detailText = [item objectForKey:@"detailText"];
|
|
1006
|
+
NSString *_text = [item objectForKey:@"text"];
|
|
1007
|
+
UIImage *_image = [RCTConvert UIImage:[item objectForKey:@"image"]];
|
|
1008
|
+
CPListItem *_item;
|
|
1009
|
+
if (@available(iOS 14.0, *)) {
|
|
1010
|
+
CPListItemAccessoryType accessoryType = _showsDisclosureIndicator ? CPListItemAccessoryTypeDisclosureIndicator : CPListItemAccessoryTypeNone;
|
|
1011
|
+
_item = [[CPListItem alloc] initWithText:_text detailText:_detailText image:_image accessoryImage:nil accessoryType:accessoryType];
|
|
1012
|
+
} else {
|
|
1013
|
+
_item = [[CPListItem alloc] initWithText:_text detailText:_detailText image:_image showsDisclosureIndicator:_showsDisclosureIndicator];
|
|
1014
|
+
}
|
|
1015
|
+
if ([item objectForKey:@"isPlaying"]) {
|
|
1016
|
+
[_item setPlaying:[RCTConvert BOOL:[item objectForKey:@"isPlaying"]]];
|
|
1017
|
+
}
|
|
1018
|
+
if (item[@"imgUrl"]) {
|
|
1019
|
+
NSString *imgUrlString = [RCTConvert NSString:item[@"imgUrl"]];
|
|
1020
|
+
[self updateItemImageWithURL:_item imgUrl:imgUrlString];
|
|
1021
|
+
}
|
|
1022
|
+
[_item setUserInfo:@{ @"index": @(index) }];
|
|
1023
|
+
[_items addObject:_item];
|
|
1024
|
+
index = index + 1;
|
|
1025
|
+
}
|
|
1026
|
+
return _items;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
- (NSArray<CPInformationItem*>*)parseInformationItems:(NSArray*)items {
|
|
1030
|
+
NSMutableArray *_items = [NSMutableArray array];
|
|
1031
|
+
for (NSDictionary *item in items) {
|
|
1032
|
+
[_items addObject:[[CPInformationItem alloc] initWithTitle:item[@"title"] detail:item[@"detail"]]];
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
return _items;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
- (NSArray<CPTextButton*>*)parseInformationActions:(NSArray*)actions templateId:(NSString *)templateId {
|
|
1039
|
+
NSMutableArray *_actions = [NSMutableArray array];
|
|
1040
|
+
for (NSDictionary *action in actions) {
|
|
1041
|
+
CPTextButton *_action = [[CPTextButton alloc] initWithTitle:action[@"title"] textStyle:CPTextButtonStyleNormal handler:^(__kindof CPTextButton * _Nonnull contactButton) {
|
|
1042
|
+
if (self->hasListeners) {
|
|
1043
|
+
[self sendEventWithName:@"actionButtonPressed" body:@{@"templateId":templateId, @"id": action[@"id"] }];
|
|
1044
|
+
}
|
|
1045
|
+
}];
|
|
1046
|
+
[_actions addObject:_action];
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return _actions;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
- (NSArray<CPGridButton*>*)parseGridButtons:(NSArray*)buttons templateId:(NSString*)templateId {
|
|
1054
|
+
NSMutableArray *result = [NSMutableArray array];
|
|
1055
|
+
int index = 0;
|
|
1056
|
+
for (NSDictionary *button in buttons) {
|
|
1057
|
+
NSString *_id = [button objectForKey:@"id"];
|
|
1058
|
+
NSArray<NSString*> *_titleVariants = [button objectForKey:@"titleVariants"];
|
|
1059
|
+
UIImage *_image = [RCTConvert UIImage:[button objectForKey:@"image"]];
|
|
1060
|
+
CPGridButton *_button = [[CPGridButton alloc] initWithTitleVariants:_titleVariants image:_image handler:^(CPGridButton * _Nonnull barButton) {
|
|
1061
|
+
if (self->hasListeners) {
|
|
1062
|
+
[self sendEventWithName:@"gridButtonPressed" body:@{@"id": _id, @"templateId":templateId, @"index": @(index) }];
|
|
1063
|
+
}
|
|
1064
|
+
}];
|
|
1065
|
+
BOOL _disabled = [button objectForKey:@"disabled"];
|
|
1066
|
+
[_button setEnabled:!_disabled];
|
|
1067
|
+
[result addObject:_button];
|
|
1068
|
+
index = index + 1;
|
|
1069
|
+
}
|
|
1070
|
+
return result;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
- (CPTravelEstimates*)parseTravelEstimates: (NSDictionary*)json {
|
|
1074
|
+
NSString *units = [RCTConvert NSString:json[@"distanceUnits"]];
|
|
1075
|
+
double value = [RCTConvert double:json[@"distanceRemaining"]];
|
|
1076
|
+
|
|
1077
|
+
NSUnit *unit = [NSUnitLength kilometers];
|
|
1078
|
+
if (units && [units isEqualToString: @"meters"]) {
|
|
1079
|
+
unit = [NSUnitLength meters];
|
|
1080
|
+
}
|
|
1081
|
+
else if (units && [units isEqualToString: @"miles"]) {
|
|
1082
|
+
unit = [NSUnitLength miles];
|
|
1083
|
+
}
|
|
1084
|
+
else if (units && [units isEqualToString: @"feet"]) {
|
|
1085
|
+
unit = [NSUnitLength feet];
|
|
1086
|
+
}
|
|
1087
|
+
else if (units && [units isEqualToString: @"yards"]) {
|
|
1088
|
+
unit = [NSUnitLength yards];
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
NSMeasurement *distance = [[NSMeasurement alloc] initWithDoubleValue:value unit:unit];
|
|
1092
|
+
double time = [RCTConvert double:json[@"timeRemaining"]];
|
|
1093
|
+
|
|
1094
|
+
return [[CPTravelEstimates alloc] initWithDistanceRemaining:distance timeRemaining:time];
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
- (CPManeuver*)parseManeuver:(NSDictionary*)json {
|
|
1098
|
+
CPManeuver* maneuver = [[CPManeuver alloc] init];
|
|
1099
|
+
|
|
1100
|
+
if ([json objectForKey:@"junctionImage"]) {
|
|
1101
|
+
UIImage *junctionImage = [RCTConvert UIImage:json[@"junctionImage"]];
|
|
1102
|
+
[maneuver setJunctionImage:[self imageWithTint:junctionImage andTintColor:[UIColor whiteColor]]];
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if ([json objectForKey:@"initialTravelEstimates"]) {
|
|
1106
|
+
CPTravelEstimates* travelEstimates = [self parseTravelEstimates:json[@"initialTravelEstimates"]];
|
|
1107
|
+
[maneuver setInitialTravelEstimates:travelEstimates];
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
if ([json objectForKey:@"symbolImage"]) {
|
|
1111
|
+
UIImage *symbolImage = [RCTConvert UIImage:json[@"symbolImage"]];
|
|
1112
|
+
|
|
1113
|
+
if ([json objectForKey:@"symbolImageSize"]) {
|
|
1114
|
+
NSDictionary *size = [RCTConvert NSDictionary:json[@"symbolImageSize"]];
|
|
1115
|
+
double width = [RCTConvert double:size[@"width"]];
|
|
1116
|
+
double height = [RCTConvert double:size[@"height"]];
|
|
1117
|
+
symbolImage = [self imageWithSize:symbolImage convertToSize:CGSizeMake(width, height)];
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
BOOL shouldTint = [RCTConvert BOOL:json[@"tintSymbolImage"]];
|
|
1121
|
+
if ([json objectForKey:@"tintSymbolImage"]) {
|
|
1122
|
+
UIColor *tintColor = [RCTConvert UIColor:json[@"tintSymbolImage"]];
|
|
1123
|
+
UIImage *darkImage = symbolImage;
|
|
1124
|
+
UIImage *lightImage = [self imageWithTint:symbolImage andTintColor:tintColor];
|
|
1125
|
+
symbolImage = [self dynamicImageWithNormalImage:lightImage darkImage:darkImage];
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
[maneuver setSymbolImage:symbolImage];
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if ([json objectForKey:@"instructionVariants"]) {
|
|
1133
|
+
[maneuver setInstructionVariants:[RCTConvert NSStringArray:json[@"instructionVariants"]]];
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return maneuver;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
- (CPTripPreviewTextConfiguration*)parseTripPreviewTextConfiguration:(NSDictionary*)json {
|
|
1140
|
+
return [[CPTripPreviewTextConfiguration alloc] initWithStartButtonTitle:[RCTConvert NSString:json[@"startButtonTitle"]] additionalRoutesButtonTitle:[RCTConvert NSString:json[@"additionalRoutesButtonTitle"]] overviewButtonTitle:[RCTConvert NSString:json[@"overviewButtonTitle"]]];
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
- (CPTrip*)parseTrip:(NSDictionary*)config {
|
|
1144
|
+
if ([config objectForKey:@"config"]) {
|
|
1145
|
+
config = [config objectForKey:@"config"];
|
|
1146
|
+
}
|
|
1147
|
+
MKMapItem *origin = [RCTConvert MKMapItem:config[@"origin"]];
|
|
1148
|
+
MKMapItem *destination = [RCTConvert MKMapItem:config[@"destination"]];
|
|
1149
|
+
NSMutableArray *routeChoices = [NSMutableArray array];
|
|
1150
|
+
if ([config objectForKey:@"routeChoices"]) {
|
|
1151
|
+
NSInteger index = 0;
|
|
1152
|
+
for (NSDictionary *routeChoice in [RCTConvert NSArray:config[@"routeChoices"]]) {
|
|
1153
|
+
CPRouteChoice *cpRouteChoice = [RCTConvert CPRouteChoice:routeChoice];
|
|
1154
|
+
NSMutableDictionary *userInfo = cpRouteChoice.userInfo;
|
|
1155
|
+
if (!userInfo) {
|
|
1156
|
+
userInfo = [[NSMutableDictionary alloc] init];
|
|
1157
|
+
cpRouteChoice.userInfo = userInfo;
|
|
1158
|
+
}
|
|
1159
|
+
[userInfo setValue:[NSNumber numberWithInteger:index] forKey:@"index"];
|
|
1160
|
+
[routeChoices addObject:cpRouteChoice];
|
|
1161
|
+
index++;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return [[CPTrip alloc] initWithOrigin:origin destination:destination routeChoices:routeChoices];
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
- (CPNavigationAlert*)parseNavigationAlert:(NSDictionary*)json templateId:(NSString*)templateId {
|
|
1168
|
+
CPImageSet *imageSet;
|
|
1169
|
+
if ([json objectForKey:@"lightImage"] && [json objectForKey:@"darkImage"]) {
|
|
1170
|
+
imageSet = [[CPImageSet alloc] initWithLightContentImage:[RCTConvert UIImage:json[@"lightImage"]] darkContentImage:[RCTConvert UIImage:json[@"darkImage"]]];
|
|
1171
|
+
}
|
|
1172
|
+
CPAlertAction *secondaryAction = [json objectForKey:@"secondaryAction"] ? [self parseAlertAction:json[@"secondaryAction"] body:@{ @"templateId": templateId, @"secondary": @(YES) }] : nil;
|
|
1173
|
+
|
|
1174
|
+
return [[CPNavigationAlert alloc] initWithTitleVariants:[RCTConvert NSStringArray:json[@"titleVariants"]] subtitleVariants:[RCTConvert NSStringArray:json[@"subtitleVariants"]] imageSet:imageSet primaryAction:[self parseAlertAction:json[@"primaryAction"] body:@{ @"templateId": templateId, @"primary": @(YES) }] secondaryAction:secondaryAction duration:[RCTConvert double:json[@"duration"]]];
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
- (CPAlertAction*)parseAlertAction:(NSDictionary*)json body:(NSDictionary*)body {
|
|
1178
|
+
return [[CPAlertAction alloc] initWithTitle:[RCTConvert NSString:json[@"title"]] style:(CPAlertActionStyle) [RCTConvert NSUInteger:json[@"style"]] handler:^(CPAlertAction * _Nonnull action) {
|
|
1179
|
+
if (self->hasListeners) {
|
|
1180
|
+
[self sendEventWithName:@"alertActionPressed" body:body];
|
|
1181
|
+
}
|
|
1182
|
+
}];
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
- (NSArray<CPVoiceControlState*>*)parseVoiceControlStates:(NSArray<NSDictionary*>*)items {
|
|
1186
|
+
NSMutableArray<CPVoiceControlState*>* res = [NSMutableArray array];
|
|
1187
|
+
for (NSDictionary *item in items) {
|
|
1188
|
+
[res addObject:[self parseVoiceControlState:item]];
|
|
1189
|
+
}
|
|
1190
|
+
return res;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
- (CPVoiceControlState*)parseVoiceControlState:(NSDictionary*)json {
|
|
1194
|
+
return [[CPVoiceControlState alloc] initWithIdentifier:[RCTConvert NSString:json[@"identifier"]] titleVariants:[RCTConvert NSStringArray:json[@"titleVariants"]] image:[RCTConvert UIImage:json[@"image"]] repeats:[RCTConvert BOOL:json[@"repeats"]]];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
- (NSString*)panDirectionToString:(CPPanDirection)panDirection {
|
|
1198
|
+
switch (panDirection) {
|
|
1199
|
+
case CPPanDirectionUp: return @"up";
|
|
1200
|
+
case CPPanDirectionRight: return @"right";
|
|
1201
|
+
case CPPanDirectionDown: return @"down";
|
|
1202
|
+
case CPPanDirectionLeft: return @"left";
|
|
1203
|
+
case CPPanDirectionNone: return @"none";
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
- (NSDictionary*)navigationAlertToJson:(CPNavigationAlert*)navigationAlert dismissalContext:(CPNavigationAlertDismissalContext)dismissalContext {
|
|
1208
|
+
NSString *dismissalCtx = @"none";
|
|
1209
|
+
if (dismissalContext) {
|
|
1210
|
+
switch (dismissalContext) {
|
|
1211
|
+
case CPNavigationAlertDismissalContextTimeout:
|
|
1212
|
+
dismissalCtx = @"timeout";
|
|
1213
|
+
break;
|
|
1214
|
+
case CPNavigationAlertDismissalContextSystemDismissed:
|
|
1215
|
+
dismissalCtx = @"system";
|
|
1216
|
+
break;
|
|
1217
|
+
case CPNavigationAlertDismissalContextUserDismissed:
|
|
1218
|
+
dismissalCtx = @"user";
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
return @{
|
|
1224
|
+
@"todo": @(YES),
|
|
1225
|
+
@"reason": dismissalCtx
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
- (NSDictionary*)navigationAlertToJson:(CPNavigationAlert*)navigationAlert {
|
|
1229
|
+
return @{ @"todo": @(YES) };
|
|
1230
|
+
// NSMutableDictionary *res = [[NSMutableDictionary alloc] init];
|
|
1231
|
+
// return @{
|
|
1232
|
+
// };
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
- (void)sendTemplateEventWithName:(CPTemplate *)template name:(NSString*)name {
|
|
1236
|
+
[self sendTemplateEventWithName:template name:name json:@{}];
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
- (void)sendTemplateEventWithName:(CPTemplate *)template name:(NSString*)name json:(NSDictionary*)json {
|
|
1240
|
+
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:json];
|
|
1241
|
+
NSDictionary *userInfo = [template userInfo];
|
|
1242
|
+
if(userInfo){
|
|
1243
|
+
[body setObject:[userInfo objectForKey:@"templateId"] forKey:@"templateId"];
|
|
1244
|
+
if(hasListeners) {
|
|
1245
|
+
[self sendEventWithName:name body:body];
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
# pragma MapTemplate
|
|
1252
|
+
|
|
1253
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate selectedPreviewForTrip:(CPTrip *)trip usingRouteChoice:(CPRouteChoice *)routeChoice {
|
|
1254
|
+
NSDictionary *userInfo = trip.userInfo;
|
|
1255
|
+
NSString *tripId = [userInfo valueForKey:@"id"];
|
|
1256
|
+
|
|
1257
|
+
NSDictionary *routeUserInfo = routeChoice.userInfo;
|
|
1258
|
+
NSString *routeIndex = [routeUserInfo valueForKey:@"index"];
|
|
1259
|
+
[self sendTemplateEventWithName:mapTemplate name:@"selectedPreviewForTrip" json:@{ @"tripId": tripId, @"routeIndex": routeIndex}];
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate startedTrip:(CPTrip *)trip usingRouteChoice:(CPRouteChoice *)routeChoice {
|
|
1263
|
+
NSDictionary *userInfo = trip.userInfo;
|
|
1264
|
+
NSString *tripId = [userInfo valueForKey:@"id"];
|
|
1265
|
+
|
|
1266
|
+
NSDictionary *routeUserInfo = routeChoice.userInfo;
|
|
1267
|
+
NSString *routeIndex = [routeUserInfo valueForKey:@"index"];
|
|
1268
|
+
|
|
1269
|
+
[self sendTemplateEventWithName:mapTemplate name:@"startedTrip" json:@{ @"tripId": tripId, @"routeIndex": routeIndex}];
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
- (void)mapTemplateDidCancelNavigation:(CPMapTemplate *)mapTemplate {
|
|
1273
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didCancelNavigation"];
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
//- (BOOL)mapTemplate:(CPMapTemplate *)mapTemplate shouldShowNotificationForManeuver:(CPManeuver *)maneuver {
|
|
1277
|
+
// // @todo
|
|
1278
|
+
//}
|
|
1279
|
+
//- (BOOL)mapTemplate:(CPMapTemplate *)mapTemplate shouldUpdateNotificationForManeuver:(CPManeuver *)maneuver withTravelEstimates:(CPTravelEstimates *)travelEstimates {
|
|
1280
|
+
// // @todo
|
|
1281
|
+
//}
|
|
1282
|
+
//- (BOOL)mapTemplate:(CPMapTemplate *)mapTemplate shouldShowNotificationForNavigationAlert:(CPNavigationAlert *)navigationAlert {
|
|
1283
|
+
// // @todo
|
|
1284
|
+
//}
|
|
1285
|
+
|
|
1286
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate willShowNavigationAlert:(CPNavigationAlert *)navigationAlert {
|
|
1287
|
+
[self sendTemplateEventWithName:mapTemplate name:@"willShowNavigationAlert" json:[self navigationAlertToJson:navigationAlert]];
|
|
1288
|
+
}
|
|
1289
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate didShowNavigationAlert:(CPNavigationAlert *)navigationAlert {
|
|
1290
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didShowNavigationAlert" json:[self navigationAlertToJson:navigationAlert]];
|
|
1291
|
+
}
|
|
1292
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate willDismissNavigationAlert:(CPNavigationAlert *)navigationAlert dismissalContext:(CPNavigationAlertDismissalContext)dismissalContext {
|
|
1293
|
+
[self sendTemplateEventWithName:mapTemplate name:@"willDismissNavigationAlert" json:[self navigationAlertToJson:navigationAlert dismissalContext:dismissalContext]];
|
|
1294
|
+
}
|
|
1295
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate didDismissNavigationAlert:(CPNavigationAlert *)navigationAlert dismissalContext:(CPNavigationAlertDismissalContext)dismissalContext {
|
|
1296
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didDismissNavigationAlert" json:[self navigationAlertToJson:navigationAlert dismissalContext:dismissalContext]];
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
- (void)mapTemplateDidShowPanningInterface:(CPMapTemplate *)mapTemplate {
|
|
1300
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didShowPanningInterface"];
|
|
1301
|
+
}
|
|
1302
|
+
- (void)mapTemplateWillDismissPanningInterface:(CPMapTemplate *)mapTemplate {
|
|
1303
|
+
[self sendTemplateEventWithName:mapTemplate name:@"willDismissPanningInterface"];
|
|
1304
|
+
}
|
|
1305
|
+
- (void)mapTemplateDidDismissPanningInterface:(CPMapTemplate *)mapTemplate {
|
|
1306
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didDismissPanningInterface"];
|
|
1307
|
+
}
|
|
1308
|
+
- (void)mapTemplateDidBeginPanGesture:(CPMapTemplate *)mapTemplate {
|
|
1309
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didBeginPanGesture"];
|
|
1310
|
+
}
|
|
1311
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panWithDirection:(CPPanDirection)direction {
|
|
1312
|
+
[self sendTemplateEventWithName:mapTemplate name:@"panWithDirection" json:@{ @"direction": [self panDirectionToString:direction] }];
|
|
1313
|
+
}
|
|
1314
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panBeganWithDirection:(CPPanDirection)direction {
|
|
1315
|
+
[self sendTemplateEventWithName:mapTemplate name:@"panBeganWithDirection" json:@{ @"direction": [self panDirectionToString:direction] }];
|
|
1316
|
+
}
|
|
1317
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panEndedWithDirection:(CPPanDirection)direction {
|
|
1318
|
+
[self sendTemplateEventWithName:mapTemplate name:@"panEndedWithDirection" json:@{ @"direction": [self panDirectionToString:direction] }];
|
|
1319
|
+
}
|
|
1320
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate didEndPanGestureWithVelocity:(CGPoint)velocity {
|
|
1321
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didEndPanGestureWithVelocity" json:@{ @"velocity": @{ @"x": @(velocity.x), @"y": @(velocity.y) }}];
|
|
1322
|
+
}
|
|
1323
|
+
- (void)mapTemplate:(CPMapTemplate *)mapTemplate didUpdatePanGestureWithTranslation:(CGPoint)translation velocity:(CGPoint)velocity {
|
|
1324
|
+
[self sendTemplateEventWithName:mapTemplate name:@"didUpdatePanGestureWithTranslation" json:@{ @"translation": @{ @"x": @(translation.x), @"y": @(translation.y) }, @"velocity": @{ @"x": @(velocity.x), @"y": @(velocity.y) }}];
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
# pragma SearchTemplate
|
|
1330
|
+
|
|
1331
|
+
- (void)searchTemplate:(CPSearchTemplate *)searchTemplate selectedResult:(CPListItem *)item completionHandler:(void (^)(void))completionHandler {
|
|
1332
|
+
NSNumber* index = [item.userInfo objectForKey:@"index"];
|
|
1333
|
+
[self sendTemplateEventWithName:searchTemplate name:@"selectedResult" json:@{ @"index": index }];
|
|
1334
|
+
self.selectedResultBlock = completionHandler;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
- (void)searchTemplateSearchButtonPressed:(CPSearchTemplate *)searchTemplate {
|
|
1338
|
+
[self sendTemplateEventWithName:searchTemplate name:@"searchButtonPressed"];
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
- (void)searchTemplate:(CPSearchTemplate *)searchTemplate updatedSearchText:(NSString *)searchText completionHandler:(void (^)(NSArray<CPListItem *> * _Nonnull))completionHandler {
|
|
1342
|
+
[self sendTemplateEventWithName:searchTemplate name:@"updatedSearchText" json:@{ @"searchText": searchText }];
|
|
1343
|
+
self.searchResultBlock = completionHandler;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
# pragma ListTemplate
|
|
1347
|
+
|
|
1348
|
+
- (void)listTemplate:(CPListTemplate *)listTemplate didSelectListItem:(CPListItem *)item completionHandler:(void (^)(void))completionHandler {
|
|
1349
|
+
NSNumber* index = [item.userInfo objectForKey:@"index"];
|
|
1350
|
+
[self sendTemplateEventWithName:listTemplate name:@"didSelectListItem" json:@{ @"index": index }];
|
|
1351
|
+
self.selectedResultBlock = completionHandler;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
# pragma TabBarTemplate
|
|
1355
|
+
- (void)tabBarTemplate:(CPTabBarTemplate *)tabBarTemplate didSelectTemplate:(__kindof CPTemplate *)selectedTemplate {
|
|
1356
|
+
NSString* selectedTemplateId = [[selectedTemplate userInfo] objectForKey:@"templateId"];
|
|
1357
|
+
[self sendTemplateEventWithName:tabBarTemplate name:@"didSelectTemplate" json:@{@"selectedTemplateId":selectedTemplateId}];
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
# pragma PointOfInterest
|
|
1361
|
+
-(void)pointOfInterestTemplate:(CPPointOfInterestTemplate *)pointOfInterestTemplate didChangeMapRegion:(MKCoordinateRegion)region {
|
|
1362
|
+
// noop
|
|
1363
|
+
|
|
1364
|
+
// NSDictionary *regionDictionary = @{
|
|
1365
|
+
// @"latitude": @(region.center.latitude),
|
|
1366
|
+
// @"longitude": @(region.center.longitude),
|
|
1367
|
+
// @"latitudeDelta": @(region.span.latitudeDelta),
|
|
1368
|
+
// @"longitudeDelta": @(region.span.longitudeDelta)
|
|
1369
|
+
// };
|
|
1370
|
+
//
|
|
1371
|
+
// [self sendTemplateEventWithName:pointOfInterestTemplate name:@"didChangeMapRegion" json:regionDictionary];
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
-(void)pointOfInterestTemplate:(CPPointOfInterestTemplate *)pointOfInterestTemplate didSelectPointOfInterest:(CPPointOfInterest *)pointOfInterest {
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
// RNCPStore *store = [RNCPStore sharedManager];
|
|
1378
|
+
// CPTemplateApplicationScene *templateApplicationScene = store.scene;
|
|
1379
|
+
//
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
//
|
|
1383
|
+
// [pointOfInterest.location openInMapsWithLaunchOptions:nil fromScene:templateApplicationScene completionHandler:^(BOOL success) {
|
|
1384
|
+
// NSLog(@"Selected map item: %@",pointOfInterest.location);
|
|
1385
|
+
// }];
|
|
1386
|
+
//
|
|
1387
|
+
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
- (void)pointOfInterestTemplate:(CPPointOfInterestTemplate *)poiTemplate didSelectMapItem:(MKMapItem *)mapItem {
|
|
1391
|
+
// Handle the selection of the map item here
|
|
1392
|
+
NSLog(@"Selected map item: %@", mapItem);
|
|
1393
|
+
|
|
1394
|
+
[mapItem openInMapsWithLaunchOptions:nil fromScene:poiTemplate completionHandler:^(BOOL success) {
|
|
1395
|
+
NSLog(@"Selected map item: %@", mapItem);
|
|
1396
|
+
}];
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
- (CPPointOfInterestTemplate *)createCarPlayPOISCreen:(CPInterfaceController *)cpInterface responseList:(NSDictionary *)responseData templateId:(NSString *)templateId {
|
|
1400
|
+
|
|
1401
|
+
NSArray<NSDictionary*> *items = [RCTConvert NSDictionaryArray:responseData[@"items"]];
|
|
1402
|
+
|
|
1403
|
+
NSMutableArray<CPPointOfInterest *> *pois = [NSMutableArray array];
|
|
1404
|
+
|
|
1405
|
+
for (NSDictionary *item in items) {
|
|
1406
|
+
|
|
1407
|
+
double latitudeValue = item[@"latitude"] && [item[@"latitude"] isKindOfClass:[NSNumber class]] ? [item[@"latitude"] doubleValue]: 0; // Extracting double value from NSNumber
|
|
1408
|
+
double longitudeValue = item[@"longitude"] && [item[@"longitude"] isKindOfClass:[NSNumber class]] ? [item[@"longitude"] doubleValue] : 0; // Extracting double value from NSNumber
|
|
1409
|
+
[pois addObject:createPOI(cpInterface,item,latitudeValue,longitudeValue,templateId)];
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
CPPointOfInterestTemplate *template = [[CPPointOfInterestTemplate alloc] initWithTitle:responseData[@"title"] pointsOfInterest:pois selectedIndex:NSNotFound];
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
|
|
1416
|
+
return template;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// Function to create a composite image with a small icon positioned to the right side and bottom of the main icon,
|
|
1420
|
+
// or a circular filled background with a specified color if the small icon is not present
|
|
1421
|
+
- (UIImage *)compositeImageWithMainIcon:(UIImage *)mainIcon smallIcon:(UIImage *)smallIcon backgroundColor:(UIColor *)backgroundColor {
|
|
1422
|
+
// Specify the desired width and height for the composite image
|
|
1423
|
+
CGFloat compositeWidth = MAX(mainIcon.size.width, smallIcon.size.width); // Use the maximum width of the two icons
|
|
1424
|
+
CGFloat compositeHeight = MAX(mainIcon.size.height, smallIcon.size.height); // Use the maximum height of the two icons
|
|
1425
|
+
|
|
1426
|
+
// Begin a new image context, to draw our composite image
|
|
1427
|
+
UIGraphicsBeginImageContextWithOptions(CGSizeMake(compositeWidth, compositeHeight), NO, 0.0);
|
|
1428
|
+
|
|
1429
|
+
// Calculate the position for drawing the main icon at the top left
|
|
1430
|
+
CGPoint mainIconPosition = CGPointZero;
|
|
1431
|
+
|
|
1432
|
+
if (smallIcon) {
|
|
1433
|
+
// If small icon is available, draw it at the right side and bottom of the main icon
|
|
1434
|
+
[mainIcon drawAtPoint:CGPointZero]; // Draw the main icon at the top left
|
|
1435
|
+
|
|
1436
|
+
// Calculate the position for drawing the small icon to the right side and bottom of the main icon
|
|
1437
|
+
CGPoint smallIconPosition = CGPointMake(mainIcon.size.width, mainIcon.size.height);
|
|
1438
|
+
[smallIcon drawAtPoint:smallIconPosition];
|
|
1439
|
+
} else {
|
|
1440
|
+
// If small icon is not available, create a circular filled background with the specified color
|
|
1441
|
+
// Draw circular filled background using the specified color
|
|
1442
|
+
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
1443
|
+
CGRect circleRect = CGRectMake(mainIcon.size.width, mainIcon.size.height, compositeWidth - mainIcon.size.width, compositeHeight - mainIcon.size.height);
|
|
1444
|
+
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
|
1445
|
+
CGContextFillEllipseInRect(context, circleRect);
|
|
1446
|
+
|
|
1447
|
+
// Draw the main icon at the top left
|
|
1448
|
+
[mainIcon drawAtPoint:CGPointZero];
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// Get the composite image from the context
|
|
1452
|
+
UIImage *compositeImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
1453
|
+
|
|
1454
|
+
// End the context
|
|
1455
|
+
UIGraphicsEndImageContext();
|
|
1456
|
+
|
|
1457
|
+
// Return the composite image
|
|
1458
|
+
return compositeImage;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
|
|
1462
|
+
CPPointOfInterest *createPOI(CPInterfaceController *cpInterface,
|
|
1463
|
+
NSDictionary *responseObj,
|
|
1464
|
+
double lat,
|
|
1465
|
+
double lng,
|
|
1466
|
+
NSString *templateId) {
|
|
1467
|
+
|
|
1468
|
+
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(lat, lng);
|
|
1469
|
+
|
|
1470
|
+
MKPlacemark *placemark =
|
|
1471
|
+
[[MKPlacemark alloc] initWithCoordinate:coordinate];
|
|
1472
|
+
|
|
1473
|
+
MKMapItem *location =
|
|
1474
|
+
[[MKMapItem alloc] initWithPlacemark:placemark];
|
|
1475
|
+
|
|
1476
|
+
// -----------------------------
|
|
1477
|
+
// Safe Title Handling
|
|
1478
|
+
// -----------------------------
|
|
1479
|
+
NSString *name = responseObj[@"title"];
|
|
1480
|
+
|
|
1481
|
+
name = (name &&
|
|
1482
|
+
![name isKindOfClass:[NSNull class]] &&
|
|
1483
|
+
name.length > 0)
|
|
1484
|
+
? name
|
|
1485
|
+
: @" ";
|
|
1486
|
+
|
|
1487
|
+
NSLog(@"UNIT ID ===> %@", name);
|
|
1488
|
+
|
|
1489
|
+
// -----------------------------
|
|
1490
|
+
// Images
|
|
1491
|
+
// -----------------------------
|
|
1492
|
+
UIImage *selectedImage =
|
|
1493
|
+
[[RNCarPlay alloc] imageFromBase64String:responseObj[@"imageUri"]];
|
|
1494
|
+
|
|
1495
|
+
selectedImage =
|
|
1496
|
+
(selectedImage &&
|
|
1497
|
+
![selectedImage isKindOfClass:[NSNull class]])
|
|
1498
|
+
? [[RNCarPlay alloc] imageWithSize:selectedImage
|
|
1499
|
+
convertToSize:CGSizeMake(100, 100)]
|
|
1500
|
+
: nil;
|
|
1501
|
+
|
|
1502
|
+
UIImage *pinImage =
|
|
1503
|
+
(selectedImage &&
|
|
1504
|
+
![selectedImage isKindOfClass:[NSNull class]])
|
|
1505
|
+
? [[RNCarPlay alloc] imageWithSize:selectedImage
|
|
1506
|
+
convertToSize:CGSizeMake(25, 25)]
|
|
1507
|
+
: nil;
|
|
1508
|
+
|
|
1509
|
+
// IMPORTANT:
|
|
1510
|
+
// Prevent CarPlay iOS 26 tint/template rendering bug
|
|
1511
|
+
if (pinImage) {
|
|
1512
|
+
pinImage =
|
|
1513
|
+
[pinImage imageWithRenderingMode:
|
|
1514
|
+
UIImageRenderingModeAlwaysOriginal];
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
if (selectedImage) {
|
|
1518
|
+
selectedImage =
|
|
1519
|
+
[selectedImage imageWithRenderingMode:
|
|
1520
|
+
UIImageRenderingModeAlwaysOriginal];
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// -----------------------------
|
|
1524
|
+
// Safe Text Handling
|
|
1525
|
+
// Use nil instead of @""
|
|
1526
|
+
// -----------------------------
|
|
1527
|
+
NSString *subtitle = responseObj[@"subtitle"];
|
|
1528
|
+
|
|
1529
|
+
subtitle = (subtitle &&
|
|
1530
|
+
![subtitle isKindOfClass:[NSNull class]] &&
|
|
1531
|
+
subtitle.length > 0)
|
|
1532
|
+
? subtitle
|
|
1533
|
+
: nil;
|
|
1534
|
+
|
|
1535
|
+
NSString *summary = responseObj[@"summary"];
|
|
1536
|
+
|
|
1537
|
+
summary = (summary &&
|
|
1538
|
+
![summary isKindOfClass:[NSNull class]] &&
|
|
1539
|
+
summary.length > 0)
|
|
1540
|
+
? summary
|
|
1541
|
+
: nil;
|
|
1542
|
+
|
|
1543
|
+
NSString *detailSubtitle =
|
|
1544
|
+
responseObj[@"detailSubtitle"];
|
|
1545
|
+
|
|
1546
|
+
detailSubtitle = (detailSubtitle &&
|
|
1547
|
+
![detailSubtitle isKindOfClass:[NSNull class]] &&
|
|
1548
|
+
detailSubtitle.length > 0)
|
|
1549
|
+
? detailSubtitle
|
|
1550
|
+
: nil;
|
|
1551
|
+
|
|
1552
|
+
NSString *detailSummary =
|
|
1553
|
+
responseObj[@"detailSummary"];
|
|
1554
|
+
|
|
1555
|
+
detailSummary = (detailSummary &&
|
|
1556
|
+
![detailSummary isKindOfClass:[NSNull class]] &&
|
|
1557
|
+
detailSummary.length > 0)
|
|
1558
|
+
? detailSummary
|
|
1559
|
+
: nil;
|
|
1560
|
+
|
|
1561
|
+
// -----------------------------
|
|
1562
|
+
// Create POI
|
|
1563
|
+
// -----------------------------
|
|
1564
|
+
CPPointOfInterest *poi;
|
|
1565
|
+
|
|
1566
|
+
if (@available(iOS 16.0, *)) {
|
|
1567
|
+
|
|
1568
|
+
poi = [[CPPointOfInterest alloc]
|
|
1569
|
+
initWithLocation:location
|
|
1570
|
+
title:name
|
|
1571
|
+
subtitle:subtitle
|
|
1572
|
+
summary:summary
|
|
1573
|
+
detailTitle:name
|
|
1574
|
+
detailSubtitle:detailSubtitle
|
|
1575
|
+
detailSummary:detailSummary
|
|
1576
|
+
pinImage:pinImage
|
|
1577
|
+
selectedPinImage:selectedImage];
|
|
1578
|
+
|
|
1579
|
+
} else {
|
|
1580
|
+
|
|
1581
|
+
poi = [[CPPointOfInterest alloc]
|
|
1582
|
+
initWithLocation:location
|
|
1583
|
+
title:name
|
|
1584
|
+
subtitle:subtitle
|
|
1585
|
+
summary:summary
|
|
1586
|
+
detailTitle:name
|
|
1587
|
+
detailSubtitle:detailSubtitle
|
|
1588
|
+
detailSummary:detailSummary
|
|
1589
|
+
pinImage:pinImage];
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// -----------------------------
|
|
1593
|
+
// First Button
|
|
1594
|
+
// -----------------------------
|
|
1595
|
+
NSDictionary *firstButtonActionInfo =
|
|
1596
|
+
responseObj[@"firstButtonActionInfo"];
|
|
1597
|
+
|
|
1598
|
+
BOOL isVisibleForFirstBtn =
|
|
1599
|
+
[firstButtonActionInfo[@"isVisible"] boolValue];
|
|
1600
|
+
|
|
1601
|
+
if (isVisibleForFirstBtn) {
|
|
1602
|
+
|
|
1603
|
+
poi.primaryButton =
|
|
1604
|
+
[[CPTextButton alloc]
|
|
1605
|
+
initWithTitle:firstButtonActionInfo[@"title"]
|
|
1606
|
+
textStyle:CPTextButtonStyleNormal
|
|
1607
|
+
handler:^(CPTextButton * _Nonnull button) {
|
|
1608
|
+
|
|
1609
|
+
[[RNCarPlay new]
|
|
1610
|
+
sendEventWithName:@"actionButtonPressed"
|
|
1611
|
+
body:@{
|
|
1612
|
+
@"templateId": templateId,
|
|
1613
|
+
@"id": firstButtonActionInfo[@"actionType"],
|
|
1614
|
+
@"responseObj": responseObj,
|
|
1615
|
+
@"latitude": @(lat),
|
|
1616
|
+
@"longitude": @(lng)
|
|
1617
|
+
}];
|
|
1618
|
+
}];
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// -----------------------------
|
|
1622
|
+
// Second Button
|
|
1623
|
+
// -----------------------------
|
|
1624
|
+
NSDictionary *secondButtonActionInfo =
|
|
1625
|
+
responseObj[@"secondButtonActionInfo"];
|
|
1626
|
+
|
|
1627
|
+
BOOL isVisibleForSecondBtn =
|
|
1628
|
+
[secondButtonActionInfo[@"isVisible"] boolValue];
|
|
1629
|
+
|
|
1630
|
+
if (isVisibleForSecondBtn) {
|
|
1631
|
+
|
|
1632
|
+
poi.secondaryButton =
|
|
1633
|
+
[[CPTextButton alloc]
|
|
1634
|
+
initWithTitle:secondButtonActionInfo[@"title"]
|
|
1635
|
+
textStyle:CPTextButtonStyleNormal
|
|
1636
|
+
handler:^(CPTextButton * _Nonnull button) {
|
|
1637
|
+
|
|
1638
|
+
NSString *mapsURLString =
|
|
1639
|
+
[NSString stringWithFormat:
|
|
1640
|
+
@"http://maps.apple.com/?ll=%f,%f",
|
|
1641
|
+
lat,
|
|
1642
|
+
lng];
|
|
1643
|
+
|
|
1644
|
+
NSLog(@"Maps URL: %@", mapsURLString);
|
|
1645
|
+
|
|
1646
|
+
[[RNCarPlay new]
|
|
1647
|
+
sendEventWithName:@"actionButtonPressed"
|
|
1648
|
+
body:@{
|
|
1649
|
+
@"templateId": templateId,
|
|
1650
|
+
@"id": secondButtonActionInfo[@"actionType"],
|
|
1651
|
+
@"responseObj": responseObj,
|
|
1652
|
+
@"latitude": @(lat),
|
|
1653
|
+
@"longitude": @(lng)
|
|
1654
|
+
}];
|
|
1655
|
+
}];
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
return poi;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
|
|
1663
|
+
// This method kept for reference
|
|
1664
|
+
CPPointOfInterest *createPOI2( CPInterfaceController *cpInterface, NSDictionary * responseObj, double lat, double lng, NSString * templateId) {
|
|
1665
|
+
|
|
1666
|
+
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(lat, lng);
|
|
1667
|
+
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate];
|
|
1668
|
+
MKMapItem *location = [[MKMapItem alloc] initWithPlacemark:placemark];
|
|
1669
|
+
NSString * name = responseObj[@"title"];
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
NSLog(@"UNIT ID ===> %@",name);
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
// Assuming you have the image "MapMarker" in your bundle
|
|
1676
|
+
// UIImage *image = [RCTConvert UIImage:responseObj[@"icon"]];
|
|
1677
|
+
|
|
1678
|
+
|
|
1679
|
+
|
|
1680
|
+
UIImage * selectedImage = [[RNCarPlay alloc] imageFromBase64String:responseObj[@"imageUri"]];
|
|
1681
|
+
|
|
1682
|
+
selectedImage = (selectedImage && ![selectedImage isKindOfClass:[NSNull class]]) ? [[RNCarPlay alloc] imageWithSize:selectedImage convertToSize:CGSizeMake(100, 100)] : nil;
|
|
1683
|
+
|
|
1684
|
+
UIImage * pinImage = (selectedImage && ![selectedImage isKindOfClass:[NSNull class]]) ? [[RNCarPlay alloc] imageWithSize:selectedImage convertToSize:CGSizeMake(25, 25)] : nil;
|
|
1685
|
+
|
|
1686
|
+
NSString *subtitle = responseObj[@"subtitle"];
|
|
1687
|
+
subtitle = (subtitle && subtitle != [NSNull null]) ? subtitle : @"";
|
|
1688
|
+
|
|
1689
|
+
NSString *summary = responseObj[@"summary"];
|
|
1690
|
+
summary = (summary && summary != [NSNull null]) ? summary : @"";
|
|
1691
|
+
|
|
1692
|
+
NSString *detailSubtitle = responseObj[@"detailSubtitle"];
|
|
1693
|
+
detailSubtitle = (detailSubtitle && detailSubtitle != [NSNull null]) ? detailSubtitle : @"";
|
|
1694
|
+
|
|
1695
|
+
NSString *detailSummary = responseObj[@"detailSummary"];
|
|
1696
|
+
detailSummary = (detailSummary && detailSummary != [NSNull null]) ? detailSummary : @"";
|
|
1697
|
+
|
|
1698
|
+
|
|
1699
|
+
CPPointOfInterest *poi;
|
|
1700
|
+
|
|
1701
|
+
if (@available(iOS 16.0, *)) {
|
|
1702
|
+
poi = [[CPPointOfInterest alloc] initWithLocation:location
|
|
1703
|
+
title:name
|
|
1704
|
+
subtitle:subtitle
|
|
1705
|
+
summary:summary
|
|
1706
|
+
detailTitle:name
|
|
1707
|
+
detailSubtitle:detailSubtitle
|
|
1708
|
+
detailSummary:detailSummary
|
|
1709
|
+
pinImage:pinImage
|
|
1710
|
+
selectedPinImage:selectedImage];
|
|
1711
|
+
}
|
|
1712
|
+
else{
|
|
1713
|
+
poi = [[CPPointOfInterest alloc] initWithLocation:location
|
|
1714
|
+
title:name
|
|
1715
|
+
subtitle:subtitle
|
|
1716
|
+
summary:summary
|
|
1717
|
+
detailTitle:name
|
|
1718
|
+
detailSubtitle:detailSubtitle
|
|
1719
|
+
detailSummary:detailSummary
|
|
1720
|
+
pinImage:pinImage];
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
NSDictionary *firstButtonActionInfo = responseObj[@"firstButtonActionInfo"];
|
|
1724
|
+
NSNumber *isVisibleNumber = firstButtonActionInfo[@"isVisible"];
|
|
1725
|
+
BOOL isVisibleForFirstBtn = [isVisibleNumber boolValue];
|
|
1726
|
+
|
|
1727
|
+
if(isVisibleForFirstBtn){
|
|
1728
|
+
poi.primaryButton = [[CPTextButton alloc] initWithTitle:firstButtonActionInfo[@"title"] textStyle:CPTextButtonStyleNormal handler:^(CPTextButton * _Nonnull button) {
|
|
1729
|
+
// [cpInterface pushTemplate:createCarParkDetailScreen(cpInterface, responseObj[@"eventDetail"])
|
|
1730
|
+
// animated:true completion:nil];
|
|
1731
|
+
|
|
1732
|
+
[[RNCarPlay new] sendEventWithName:@"actionButtonPressed"
|
|
1733
|
+
body:@{@"templateId": templateId,
|
|
1734
|
+
@"id": firstButtonActionInfo[@"actionType"],
|
|
1735
|
+
@"responseObj":responseObj,
|
|
1736
|
+
@"latitude": @(lat),
|
|
1737
|
+
@"longitude": @(lng)}];
|
|
1738
|
+
}];
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
NSDictionary *secondButtonActionInfo = responseObj[@"secondButtonActionInfo"];
|
|
1742
|
+
BOOL isVisibleForSecondBtn= [secondButtonActionInfo[@"isVisible"] boolValue];
|
|
1743
|
+
|
|
1744
|
+
if(isVisibleForSecondBtn){
|
|
1745
|
+
poi.secondaryButton = [[CPTextButton alloc] initWithTitle:responseObj[@"secondButtonActionInfo"][@"title"] textStyle:CPTextButtonStyleNormal handler:^(CPTextButton * _Nonnull button) {
|
|
1746
|
+
|
|
1747
|
+
NSString *mapsURLString = [NSString stringWithFormat:@"http://maps.apple.com/?ll=%f,%f", lat, lng];
|
|
1748
|
+
|
|
1749
|
+
//[[RNCarPlay new] openUrl:mapsURLString];
|
|
1750
|
+
|
|
1751
|
+
[[RNCarPlay new] sendEventWithName:@"actionButtonPressed"
|
|
1752
|
+
body:@{@"templateId": templateId,
|
|
1753
|
+
@"id": responseObj[@"secondButtonActionInfo"][@"actionType"],
|
|
1754
|
+
@"responseObj":responseObj,
|
|
1755
|
+
@"latitude": @(lat),
|
|
1756
|
+
@"longitude": @(lng)}];
|
|
1757
|
+
}];
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
return poi;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
|
|
1764
|
+
//UIGraphicsBeginImageContext(newSize);
|
|
1765
|
+
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
|
|
1766
|
+
// Pass 1.0 to force exact pixel size.
|
|
1767
|
+
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
|
|
1768
|
+
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
|
|
1769
|
+
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
1770
|
+
UIGraphicsEndImageContext();
|
|
1771
|
+
return newImage;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
// Function to convert Base64 encoded string to UIImage
|
|
1775
|
+
- (UIImage *)imageFromBase64String:(NSString *)base64String {
|
|
1776
|
+
// Check if the string is not empty
|
|
1777
|
+
if (base64String && ![base64String isEqualToString:@""]) {
|
|
1778
|
+
// Convert the Base64 encoded string to NSData
|
|
1779
|
+
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:base64String options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
|
1780
|
+
|
|
1781
|
+
// Initialize UIImage with the NSData
|
|
1782
|
+
UIImage *image = [UIImage imageWithData:imageData];
|
|
1783
|
+
|
|
1784
|
+
return image;
|
|
1785
|
+
} else {
|
|
1786
|
+
// Return nil if the string is empty
|
|
1787
|
+
return nil;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
|
|
1792
|
+
CPTemplate *createCarParkDetailScreen(CPInterfaceController *cpInterface, NSArray * eventDetailArr) {
|
|
1793
|
+
|
|
1794
|
+
NSMutableArray<CPInformationItem *> *lines = [NSMutableArray array];
|
|
1795
|
+
|
|
1796
|
+
for (NSDictionary *item in eventDetailArr) {
|
|
1797
|
+
[lines addObject:[[CPInformationItem alloc] initWithTitle:item[@"title"] detail:item[@"detail"]]];
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
NSMutableArray<CPTextButton *> *actions = [NSMutableArray array];
|
|
1801
|
+
|
|
1802
|
+
[actions addObject:[[CPTextButton alloc] initWithTitle:@"Done" textStyle:CPTextButtonStyleConfirm handler:^(CPTextButton * _Nonnull button) {
|
|
1803
|
+
[cpInterface popTemplateAnimated:YES completion:nil];
|
|
1804
|
+
}]];
|
|
1805
|
+
|
|
1806
|
+
CPInformationTemplate *template = [[CPInformationTemplate alloc] initWithTitle:@"Details" layout:CPInformationTemplateLayoutTwoColumn items:lines actions:actions];
|
|
1807
|
+
|
|
1808
|
+
return template;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
# pragma InterfaceController
|
|
1812
|
+
|
|
1813
|
+
- (void)templateDidAppear:(CPTemplate *)aTemplate animated:(BOOL)animated {
|
|
1814
|
+
[self sendTemplateEventWithName:aTemplate name:@"didAppear" json:@{ @"animated": @(animated) }];
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
- (void)templateDidDisappear:(CPTemplate *)aTemplate animated:(BOOL)animated {
|
|
1818
|
+
[self sendTemplateEventWithName:aTemplate name:@"didDisappear" json:@{ @"animated": @(animated) }];
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
- (void)templateWillAppear:(CPTemplate *)aTemplate animated:(BOOL)animated {
|
|
1822
|
+
[self sendTemplateEventWithName:aTemplate name:@"willAppear" json:@{ @"animated": @(animated) }];
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
- (void)templateWillDisappear:(CPTemplate *)aTemplate animated:(BOOL)animated {
|
|
1826
|
+
[self sendTemplateEventWithName:aTemplate name:@"willDisappear" json:@{ @"animated": @(animated) }];
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
# pragma NowPlaying
|
|
1830
|
+
|
|
1831
|
+
- (void)nowPlayingTemplateUpNextButtonTapped:(CPNowPlayingTemplate *)nowPlayingTemplate {
|
|
1832
|
+
[self sendTemplateEventWithName:nowPlayingTemplate name:@"upNextButtonPressed"];
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
- (void)nowPlayingTemplateAlbumArtistButtonTapped:(CPNowPlayingTemplate *)nowPlayingTemplate {
|
|
1836
|
+
[self sendTemplateEventWithName:nowPlayingTemplate name:@"albumArtistButtonPressed"];
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
@end
|