@javascriptcommon/react-native-carplay 2.3.11 → 2.4.2
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/android/build.gradle +110 -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/src/main/AndroidManifest.xml +30 -0
- package/android/src/main/AndroidManifestNew.xml +30 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayModule.kt +321 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayPackage.kt +18 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayService.kt +35 -0
- package/android/src/main/java/org/birkir/carplay/CarPlaySession.kt +126 -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 +128 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTMessageTemplate.kt +28 -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 +157 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTTemplate.kt +419 -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 +76 -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 +167 -0
- package/android/src/main/java/org/birkir/carplay/utils/VirtualRenderer.kt +75 -0
- package/ios/RCTConvert+RNCarPlay.h +7 -8
- package/ios/RCTConvert+RNCarPlay.m +4 -3
- package/ios/RNCarPlay.h +11 -14
- package/ios/RNCarPlay.m +749 -945
- package/ios/RNCarPlayViewController.h +10 -0
- package/ios/RNCarPlayViewController.m +50 -0
- package/lib/CarPlay.d.ts +183 -0
- package/lib/CarPlay.d.ts.map +1 -0
- package/lib/index.d.ts +44 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/interfaces/Action.d.ts +13 -0
- package/lib/interfaces/Action.d.ts.map +1 -0
- package/lib/interfaces/AlertAction.d.ts +6 -0
- package/lib/interfaces/AlertAction.d.ts.map +1 -0
- package/lib/interfaces/BarButton.d.ts +39 -0
- package/lib/interfaces/BarButton.d.ts.map +1 -0
- package/lib/interfaces/CarColor.d.ts +2 -0
- package/lib/interfaces/CarColor.d.ts.map +1 -0
- package/lib/interfaces/GridButton.d.ts +24 -0
- package/lib/interfaces/GridButton.d.ts.map +1 -0
- package/lib/interfaces/Header.d.ts +15 -0
- package/lib/interfaces/Header.d.ts.map +1 -0
- package/lib/interfaces/ListItem.d.ts +90 -0
- package/lib/interfaces/ListItem.d.ts.map +1 -0
- package/lib/interfaces/ListItemUpdate.d.ts +15 -0
- package/lib/interfaces/ListItemUpdate.d.ts.map +1 -0
- package/lib/interfaces/ListSection.d.ts +21 -0
- package/lib/interfaces/ListSection.d.ts.map +1 -0
- package/lib/interfaces/Maneuver.d.ts +31 -0
- package/lib/interfaces/Maneuver.d.ts.map +1 -0
- package/lib/interfaces/MapButton.d.ts +27 -0
- package/lib/interfaces/MapButton.d.ts.map +1 -0
- package/lib/interfaces/NavigationAlert.d.ts +44 -0
- package/lib/interfaces/NavigationAlert.d.ts.map +1 -0
- package/lib/interfaces/NavigationInfo.d.ts +17 -0
- package/lib/interfaces/NavigationInfo.d.ts.map +1 -0
- package/lib/interfaces/NavigationStep.d.ts +17 -0
- package/lib/interfaces/NavigationStep.d.ts.map +1 -0
- package/lib/interfaces/Pane.d.ts +29 -0
- package/lib/interfaces/Pane.d.ts.map +1 -0
- package/lib/interfaces/PauseReason.d.ts +8 -0
- package/lib/interfaces/PauseReason.d.ts.map +1 -0
- package/lib/interfaces/Place.d.ts +11 -0
- package/lib/interfaces/Place.d.ts.map +1 -0
- package/lib/interfaces/TextConfiguration.d.ts +6 -0
- package/lib/interfaces/TextConfiguration.d.ts.map +1 -0
- package/lib/interfaces/TimeRemainingColor.d.ts +2 -0
- package/lib/interfaces/TimeRemainingColor.d.ts.map +1 -0
- package/lib/interfaces/TravelEstimates.d.ts +37 -0
- package/lib/interfaces/TravelEstimates.d.ts.map +1 -0
- package/lib/interfaces/VoiceControlState.d.ts +8 -0
- package/lib/interfaces/VoiceControlState.d.ts.map +1 -0
- package/lib/navigation/NavigationSession.d.ts +18 -0
- package/lib/navigation/NavigationSession.d.ts.map +1 -0
- package/lib/navigation/Trip.d.ts +22 -0
- package/lib/navigation/Trip.d.ts.map +1 -0
- package/lib/templates/ActionSheetTemplate.d.ts +18 -0
- package/lib/templates/ActionSheetTemplate.d.ts.map +1 -0
- package/lib/templates/AlertTemplate.d.ts +17 -0
- package/lib/templates/AlertTemplate.d.ts.map +1 -0
- package/lib/templates/ContactTemplate.d.ts +36 -0
- package/lib/templates/ContactTemplate.d.ts.map +1 -0
- package/lib/templates/GridTemplate.d.ts +38 -0
- package/lib/templates/GridTemplate.d.ts.map +1 -0
- package/lib/templates/InformationTemplate.d.ts +28 -0
- package/lib/templates/InformationTemplate.d.ts.map +1 -0
- package/lib/templates/ListTemplate.d.ts +127 -0
- package/lib/templates/ListTemplate.d.ts.map +1 -0
- package/lib/templates/ListTemplate.js +24 -16
- package/lib/templates/MapTemplate.d.ts +171 -0
- package/lib/templates/MapTemplate.d.ts.map +1 -0
- package/lib/templates/NowPlayingTemplate.d.ts +31 -0
- package/lib/templates/NowPlayingTemplate.d.ts.map +1 -0
- package/lib/templates/PointOfInterestTemplate.d.ts +33 -0
- package/lib/templates/PointOfInterestTemplate.d.ts.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 +2 -2
- package/lib/templates/TabBarTemplate.d.ts +27 -0
- package/lib/templates/TabBarTemplate.d.ts.map +1 -0
- package/lib/templates/Template.d.ts +82 -0
- package/lib/templates/Template.d.ts.map +1 -0
- package/lib/templates/Template.js +1 -1
- package/lib/templates/VoiceControlTemplate.d.ts +18 -0
- package/lib/templates/VoiceControlTemplate.d.ts.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/MessageTemplate.d.ts +16 -0
- package/lib/templates/android/MessageTemplate.d.ts.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/PaneTemplate.d.ts +13 -0
- package/lib/templates/android/PaneTemplate.d.ts.map +1 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts +58 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts.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/RoutePreviewNavigationTemplate.d.ts +60 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts.map +1 -0
- package/package.json +3 -3
- package/react-native-carplay.podspec +3 -3
- package/src/CarPlay.ts +28 -16
- package/src/interfaces/ListItem.ts +14 -8
- package/src/interfaces/ListSection.ts +1 -1
- package/src/templates/ListTemplate.ts +64 -44
- package/src/templates/NowPlayingTemplate.ts +10 -3
- package/src/templates/SearchTemplate.ts +2 -2
- package/src/templates/Template.ts +1 -1
- package/README.md +0 -633
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
package org.birkir.carplay.parser
|
|
2
|
+
|
|
3
|
+
import androidx.car.app.CarContext
|
|
4
|
+
import androidx.car.app.model.PlaceListMapTemplate
|
|
5
|
+
import androidx.car.app.model.Template
|
|
6
|
+
import androidx.car.app.navigation.model.MapController
|
|
7
|
+
import androidx.car.app.navigation.model.MapTemplate
|
|
8
|
+
import androidx.car.app.navigation.model.NavigationTemplate
|
|
9
|
+
import androidx.car.app.navigation.model.PanModeListener
|
|
10
|
+
import androidx.car.app.navigation.model.PlaceListNavigationTemplate
|
|
11
|
+
import androidx.car.app.navigation.model.RoutePreviewNavigationTemplate
|
|
12
|
+
import com.facebook.react.bridge.ReadableMap
|
|
13
|
+
import org.birkir.carplay.screens.CarScreenContext
|
|
14
|
+
|
|
15
|
+
class RCTMapTemplate(
|
|
16
|
+
context: CarContext,
|
|
17
|
+
carScreenContext: CarScreenContext
|
|
18
|
+
) : RCTTemplate(context, carScreenContext) {
|
|
19
|
+
|
|
20
|
+
override fun parse(props: ReadableMap): Template {
|
|
21
|
+
val type = props.getString("type")
|
|
22
|
+
val actionStrip = props.getArray("actions")?.let {
|
|
23
|
+
parseActionStrip(it)
|
|
24
|
+
}
|
|
25
|
+
val header = props.getMap("header")?.let {
|
|
26
|
+
parseHeader(it)
|
|
27
|
+
}
|
|
28
|
+
val headerAction = props.getMap("headerAction")?.let {
|
|
29
|
+
parseAction(it)
|
|
30
|
+
}
|
|
31
|
+
val itemList = props.getArray("items")?.let {
|
|
32
|
+
parseItemList(it, "row")
|
|
33
|
+
}
|
|
34
|
+
val pane = props.getMap("pane")?.let {
|
|
35
|
+
parsePane(it)
|
|
36
|
+
}
|
|
37
|
+
val mapActionStrip = props.getArray("mapButtons")?.let {
|
|
38
|
+
parseActionStrip(it)
|
|
39
|
+
}
|
|
40
|
+
val panModeListener = PanModeListener { isInPanMode ->
|
|
41
|
+
if (isInPanMode) {
|
|
42
|
+
eventEmitter.didShowPanningInterface()
|
|
43
|
+
} else {
|
|
44
|
+
eventEmitter.didDismissPanningInterface()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
val mapController = MapController.Builder().apply {
|
|
48
|
+
mapActionStrip?.let { setMapActionStrip(it); }
|
|
49
|
+
setPanModeListener(panModeListener)
|
|
50
|
+
}.build()
|
|
51
|
+
when (type) {
|
|
52
|
+
"navigation" -> {
|
|
53
|
+
return NavigationTemplate.Builder().apply {
|
|
54
|
+
actionStrip?.let { setActionStrip(it) }
|
|
55
|
+
props.getString("backgroundColor")?.let {
|
|
56
|
+
setBackgroundColor(parseColor(it))
|
|
57
|
+
}
|
|
58
|
+
props.getMap("travelEstimate")?.let {
|
|
59
|
+
setDestinationTravelEstimate(parseTravelEstimate(it))
|
|
60
|
+
}
|
|
61
|
+
props.getMap("navigationInfo")?.let {
|
|
62
|
+
setNavigationInfo(parseNavigationInfo(it))
|
|
63
|
+
}
|
|
64
|
+
mapActionStrip?.let { setMapActionStrip(it) }
|
|
65
|
+
setPanModeListener(panModeListener)
|
|
66
|
+
}.build()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
"place-list-map" -> {
|
|
70
|
+
return PlaceListMapTemplate.Builder().apply {
|
|
71
|
+
actionStrip?.let { setActionStrip(it) }
|
|
72
|
+
props.getMap("anchor")?.let { setAnchor(parsePlace(it)) }
|
|
73
|
+
if (props.hasKey("currentLocationEnabled")) {
|
|
74
|
+
setCurrentLocationEnabled(props.getBoolean("currentLocationEnabled"))
|
|
75
|
+
}
|
|
76
|
+
headerAction?.let { setHeaderAction(it) }
|
|
77
|
+
itemList?.let { setItemList(it) }
|
|
78
|
+
setLoading(props.isLoading())
|
|
79
|
+
setOnContentRefreshListener {
|
|
80
|
+
// @todo eventEmitter?.contentDidRefresh
|
|
81
|
+
}
|
|
82
|
+
props.getString("title")?.let { setTitle(it) }
|
|
83
|
+
}.build()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
"place-list-navigation" -> {
|
|
87
|
+
return PlaceListNavigationTemplate.Builder().apply {
|
|
88
|
+
actionStrip?.let { setActionStrip(it) }
|
|
89
|
+
header?.let { setHeader(it) }
|
|
90
|
+
itemList?.let { setItemList(it) }
|
|
91
|
+
setLoading(props.isLoading())
|
|
92
|
+
mapActionStrip?.let { setActionStrip(it) }
|
|
93
|
+
setOnContentRefreshListener {
|
|
94
|
+
// @todo eventEmitter?.contentDidRefresh
|
|
95
|
+
}
|
|
96
|
+
setPanModeListener(panModeListener)
|
|
97
|
+
}.build()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
"route-preview" -> {
|
|
101
|
+
return RoutePreviewNavigationTemplate.Builder().apply {
|
|
102
|
+
actionStrip?.let { setActionStrip(it) }
|
|
103
|
+
header?.let { setHeader(it) }
|
|
104
|
+
headerAction?.let { setHeaderAction(headerAction) }
|
|
105
|
+
itemList?.let { setItemList(it) }
|
|
106
|
+
setLoading(props.isLoading())
|
|
107
|
+
mapActionStrip?.let { setMapActionStrip(it); }
|
|
108
|
+
props.getMap("navigateAction")?.let { setNavigateAction(parseAction(it)) }
|
|
109
|
+
setPanModeListener(panModeListener)
|
|
110
|
+
}.build()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
else -> {
|
|
114
|
+
return MapTemplate.Builder().apply {
|
|
115
|
+
header?.let { setHeader(it) }
|
|
116
|
+
itemList?.let { setItemList(it) }
|
|
117
|
+
actionStrip?.let { setActionStrip(it) }
|
|
118
|
+
setMapController(mapController)
|
|
119
|
+
pane?.let { setPane(it) }
|
|
120
|
+
}.build()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
companion object {
|
|
126
|
+
const val TAG = "RCTMapTemplate"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package org.birkir.carplay.parser
|
|
2
|
+
|
|
3
|
+
import androidx.car.app.CarContext
|
|
4
|
+
import androidx.car.app.model.MessageTemplate
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
import org.birkir.carplay.screens.CarScreenContext
|
|
7
|
+
|
|
8
|
+
class RCTMessageTemplate(
|
|
9
|
+
context: CarContext,
|
|
10
|
+
carScreenContext: CarScreenContext
|
|
11
|
+
) : RCTTemplate(context, carScreenContext) {
|
|
12
|
+
override fun parse(props: ReadableMap): MessageTemplate {
|
|
13
|
+
val message = props.getString("message") ?: "No message"
|
|
14
|
+
val messageText = parseCarText(message, props)
|
|
15
|
+
return MessageTemplate.Builder(messageText).apply {
|
|
16
|
+
props.getArray("actions")?.let { setActionStrip(parseActionStrip(it)) }
|
|
17
|
+
props.getMap("headerAction")?.let { setHeaderAction(parseAction(it)) }
|
|
18
|
+
props.getMap("icon")?.let { setIcon(parseCarIcon(it)) }
|
|
19
|
+
props.getString("title")?.let { setTitle(it) }
|
|
20
|
+
props.getString("debugMessage")?.let { setDebugMessage(it) }
|
|
21
|
+
setLoading(props.isLoading())
|
|
22
|
+
}.build()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
companion object {
|
|
26
|
+
const val TAG = "RCTMessageTemplate"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package org.birkir.carplay.parser
|
|
2
|
+
|
|
3
|
+
import androidx.car.app.CarContext
|
|
4
|
+
import androidx.car.app.model.PaneTemplate
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
import org.birkir.carplay.screens.CarScreenContext
|
|
7
|
+
|
|
8
|
+
class RCTPaneTemplate(
|
|
9
|
+
context: CarContext,
|
|
10
|
+
carScreenContext: CarScreenContext
|
|
11
|
+
) : RCTTemplate(context, carScreenContext) {
|
|
12
|
+
override fun parse(props: ReadableMap): PaneTemplate {
|
|
13
|
+
val pane = parsePane(props.getMap("pane")!!)
|
|
14
|
+
return PaneTemplate.Builder(pane).apply {
|
|
15
|
+
props.getArray("actions")?.let { setActionStrip(parseActionStrip(it)) }
|
|
16
|
+
props.getMap("headerAction")?.let { setHeaderAction(parseAction(it)) }
|
|
17
|
+
props.getString("title")?.let { setTitle(it) }
|
|
18
|
+
}.build()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
companion object {
|
|
22
|
+
const val TAG = "RCTPaneTemplate"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package org.birkir.carplay.parser
|
|
2
|
+
|
|
3
|
+
import androidx.car.app.CarContext
|
|
4
|
+
import androidx.car.app.model.SearchTemplate
|
|
5
|
+
import androidx.car.app.model.SearchTemplate.SearchCallback
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap
|
|
7
|
+
import org.birkir.carplay.screens.CarScreenContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RCTSearchTemplate(
|
|
11
|
+
context: CarContext,
|
|
12
|
+
carScreenContext: CarScreenContext
|
|
13
|
+
) : RCTTemplate(context, carScreenContext) {
|
|
14
|
+
override fun parse(props: ReadableMap): SearchTemplate {
|
|
15
|
+
return SearchTemplate.Builder(object : SearchCallback {
|
|
16
|
+
override fun onSearchTextChanged(searchText: String) {
|
|
17
|
+
eventEmitter.updatedSearchText(searchText)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun onSearchSubmitted(searchText: String) {
|
|
21
|
+
eventEmitter.searchButtonPressed(searchText)
|
|
22
|
+
}
|
|
23
|
+
}).apply {
|
|
24
|
+
props.getArray("actions")?.let { setActionStrip(parseActionStrip(it)) }
|
|
25
|
+
props.getMap("headerAction")?.let { setHeaderAction(parseAction(it)) }
|
|
26
|
+
props.getString("initialSearchText")?.let {
|
|
27
|
+
setInitialSearchText(it)
|
|
28
|
+
}
|
|
29
|
+
props.getArray("items")?.let { setItemList(parseItemList(it, "row")) }
|
|
30
|
+
setLoading(props.isLoading())
|
|
31
|
+
props.getString("searchHint")?.let { setSearchHint(it) }
|
|
32
|
+
if (props.hasKey("showKeyboardByDefault")) {
|
|
33
|
+
setShowKeyboardByDefault(props.getBoolean("showKeyboardByDefault"))
|
|
34
|
+
}
|
|
35
|
+
}.build()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
companion object {
|
|
39
|
+
const val TAG = "RCTSearchTemplate"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
package org.birkir.carplay.parser
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import androidx.car.app.CarContext
|
|
5
|
+
import androidx.car.app.model.Action
|
|
6
|
+
import androidx.car.app.model.CarIcon
|
|
7
|
+
import androidx.car.app.model.ItemList
|
|
8
|
+
import androidx.car.app.model.ListTemplate
|
|
9
|
+
import androidx.car.app.model.Row
|
|
10
|
+
import androidx.car.app.model.Tab
|
|
11
|
+
import androidx.car.app.model.TabContents
|
|
12
|
+
import androidx.car.app.model.TabTemplate
|
|
13
|
+
import androidx.car.app.model.TabTemplate.TabCallback
|
|
14
|
+
import com.facebook.react.bridge.ReadableMap
|
|
15
|
+
import org.birkir.carplay.screens.CarScreenContext
|
|
16
|
+
|
|
17
|
+
class RCTTabTemplate(
|
|
18
|
+
context: CarContext,
|
|
19
|
+
carScreenContext: CarScreenContext
|
|
20
|
+
) : RCTTemplate(context, carScreenContext) {
|
|
21
|
+
private val tabContentsMap = mutableMapOf<String, TabContents>()
|
|
22
|
+
private val tabInfoMap = mutableMapOf<String, TabInfo>()
|
|
23
|
+
private var currentTemplate: TabTemplate? = null
|
|
24
|
+
private var activeTabId: String? = null
|
|
25
|
+
private var isLoading: Boolean = false
|
|
26
|
+
|
|
27
|
+
data class TabInfo(val title: String, val icon: CarIcon, val headerAction: Action)
|
|
28
|
+
|
|
29
|
+
private val tabCallback = object : TabCallback {
|
|
30
|
+
override fun onTabSelected(tabContentId: String) {
|
|
31
|
+
Log.d(TAG, "Tab selected: $tabContentId")
|
|
32
|
+
eventEmitter.didSelectTemplate(tabContentId)
|
|
33
|
+
updateContents(tabContentId)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun parse(props: ReadableMap): TabTemplate {
|
|
38
|
+
tabInfoMap.clear()
|
|
39
|
+
isLoading = props.isLoading()
|
|
40
|
+
val builder = TabTemplate.Builder(tabCallback)
|
|
41
|
+
builder.setLoading(isLoading)
|
|
42
|
+
|
|
43
|
+
props.getArray("templates")?.let { templatesArray ->
|
|
44
|
+
for (i in 0 until templatesArray.size()) {
|
|
45
|
+
try {
|
|
46
|
+
val tabProps = templatesArray.getMap(i)
|
|
47
|
+
parseTabInfo(tabProps, builder)
|
|
48
|
+
} catch (e: Exception) {
|
|
49
|
+
Log.e(TAG, "Error parsing tab at index $i", e)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Set first tab as active
|
|
54
|
+
tabInfoMap.keys.firstOrNull()?.let { firstTabId ->
|
|
55
|
+
setActiveTab(builder, firstTabId)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
currentTemplate = builder.build()
|
|
60
|
+
return currentTemplate!!
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun parseTabInfo(tabProps: ReadableMap, builder: TabTemplate.Builder) {
|
|
64
|
+
val id = tabProps.getString("id") ?: return
|
|
65
|
+
val tab = parseTab(tabProps)
|
|
66
|
+
builder.addTab(tab)
|
|
67
|
+
|
|
68
|
+
val headerAction = tabProps.getMap("headerAction")?.let { parseAction(it) } ?: Action.APP_ICON
|
|
69
|
+
tabInfoMap[id] = TabInfo(tab.title.toString(), tab.icon, headerAction)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private fun setActiveTab(builder: TabTemplate.Builder, tabId: String) {
|
|
73
|
+
builder.setTabContents(getTabContents(tabId))
|
|
74
|
+
builder.setActiveTabContentId(tabId)
|
|
75
|
+
builder.setHeaderAction(tabInfoMap[tabId]?.headerAction ?: Action.APP_ICON)
|
|
76
|
+
activeTabId = tabId
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun buildCurrentTemplate() {
|
|
80
|
+
val builder = TabTemplate.Builder(tabCallback).setLoading(isLoading)
|
|
81
|
+
|
|
82
|
+
tabInfoMap.forEach { (id, info) ->
|
|
83
|
+
builder.addTab(Tab.Builder()
|
|
84
|
+
.setTitle(info.title)
|
|
85
|
+
.setIcon(info.icon)
|
|
86
|
+
.setContentId(id)
|
|
87
|
+
.build())
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
activeTabId?.let { activeId ->
|
|
91
|
+
setActiveTab(builder, activeId)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
currentTemplate = builder.build()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun parseTab(props: ReadableMap): Tab {
|
|
98
|
+
return Tab.Builder().apply {
|
|
99
|
+
props.getString("id")?.let { setContentId(it) }
|
|
100
|
+
val config = props.getMap("config")
|
|
101
|
+
when {
|
|
102
|
+
config != null -> {
|
|
103
|
+
setTitle(config.getString("tabTitle") ?: DEFAULT_TAB_TITLE)
|
|
104
|
+
setIcon(CarIcon.APP_ICON) // TODO: Parse custom icon if needed
|
|
105
|
+
}
|
|
106
|
+
else -> {
|
|
107
|
+
setTitle(DEFAULT_TAB_TITLE)
|
|
108
|
+
setIcon(CarIcon.APP_ICON)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}.build()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private fun getTabContents(templateId: String): TabContents {
|
|
115
|
+
return tabContentsMap.getOrPut(templateId) {
|
|
116
|
+
val screen = carScreenContext.screens[templateId]
|
|
117
|
+
val template = screen?.template
|
|
118
|
+
|
|
119
|
+
when {
|
|
120
|
+
template != null -> {
|
|
121
|
+
Log.d(TAG, "Template found for $templateId: $template")
|
|
122
|
+
TabContents.Builder(template).build()
|
|
123
|
+
}
|
|
124
|
+
else -> createDefaultTabContents(templateId)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private fun createDefaultTabContents(templateId: String): TabContents {
|
|
130
|
+
val defaultItemList = ItemList.Builder()
|
|
131
|
+
.addItem(Row.Builder().setTitle("No content available for $templateId").build())
|
|
132
|
+
.build()
|
|
133
|
+
val defaultTemplate = ListTemplate.Builder()
|
|
134
|
+
.setTitle(DEFAULT_CONTENT_TITLE)
|
|
135
|
+
.setSingleList(defaultItemList)
|
|
136
|
+
.build()
|
|
137
|
+
return TabContents.Builder(defaultTemplate).build()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private fun updateContents(tabContentId: String) {
|
|
141
|
+
Log.d(TAG, "Updating contents for tab: $tabContentId")
|
|
142
|
+
activeTabId = tabContentId
|
|
143
|
+
buildCurrentTemplate()
|
|
144
|
+
// Update the main tab screen with the new template
|
|
145
|
+
carScreenContext.screens[carScreenContext.screenMarker]?.apply {
|
|
146
|
+
setTemplate(currentTemplate, carScreenContext.screenMarker, null)
|
|
147
|
+
invalidate()
|
|
148
|
+
}
|
|
149
|
+
Log.d(TAG, "Template updated for tab $tabContentId")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
companion object {
|
|
153
|
+
const val TAG = "RCTTabTemplate"
|
|
154
|
+
private const val DEFAULT_TAB_TITLE = "Untitled Tab"
|
|
155
|
+
private const val DEFAULT_CONTENT_TITLE = "Default Content"
|
|
156
|
+
}
|
|
157
|
+
}
|