@iternio/react-native-auto-play 0.5.14-beta.1 → 0.6.0
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 +214 -29
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +5 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplate.kt +9 -2
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/NativeBackdrop.kt +40 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt +52 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/GridTemplate.kt +47 -13
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +21 -2
- package/ios/Types.swift +3 -0
- package/ios/extensions/UIImage+Toggle.swift +5 -2
- package/ios/hybrid/HybridAutoPlay.swift +28 -16
- package/ios/hybrid/HybridMapTemplate.swift +22 -5
- package/ios/scenes/AutoPlayInterfaceController.swift +261 -72
- package/ios/templates/AutoPlayMapPanelDelegate.swift +190 -0
- package/ios/templates/AutoPlayTemplate.swift +24 -2
- package/ios/templates/GridTemplate.swift +57 -57
- package/ios/templates/InformationTemplate.swift +84 -9
- package/ios/templates/ListTemplate.swift +66 -11
- package/ios/templates/MapTemplate.swift +83 -68
- package/ios/templates/MessageTemplate.swift +72 -6
- package/ios/templates/Parser.swift +564 -69
- package/ios/templates/SearchTemplate.swift +1 -1
- package/ios/templates/TemplateStore.swift +5 -15
- package/ios/utils/SymbolFont.swift +13 -28
- package/lib/Constants.d.ts +4 -0
- package/lib/Constants.js +6 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/specs/MapTemplate.nitro.d.ts +3 -1
- package/lib/templates/GridTemplate.d.ts +23 -3
- package/lib/templates/GridTemplate.js +8 -0
- package/lib/templates/InformationTemplate.d.ts +38 -12
- package/lib/templates/ListTemplate.d.ts +16 -47
- package/lib/templates/MapTemplate.d.ts +26 -2
- package/lib/templates/MapTemplate.js +16 -2
- package/lib/templates/MessageTemplate.d.ts +52 -11
- package/lib/templates/MessageTemplate.js +1 -1
- package/lib/utils/NitroOptionsPanel.d.ts +103 -0
- package/lib/utils/NitroOptionsPanel.js +63 -0
- package/lib/utils/NitroSection.d.ts +89 -2
- package/lib/utils/NitroSection.js +49 -2
- package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +1 -0
- package/nitrogen/generated/android/c++/JChargingConnector.hpp +79 -0
- package/nitrogen/generated/android/c++/JGridImageSize.hpp +64 -0
- package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +7 -1
- package/nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp +4 -0
- package/nitrogen/generated/android/c++/JHybridInformationTemplateSpec.cpp +12 -0
- package/nitrogen/generated/android/c++/JHybridListTemplateSpec.cpp +12 -0
- package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.cpp +78 -3
- package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.hpp +2 -1
- package/nitrogen/generated/android/c++/JHybridSearchTemplateSpec.cpp +12 -0
- package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +6 -0
- package/nitrogen/generated/android/c++/JListImageType.hpp +67 -0
- package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +6 -0
- package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +115 -0
- package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +82 -0
- package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +112 -0
- package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +157 -0
- package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +102 -0
- package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.cpp +30 -0
- package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.hpp +129 -0
- package/nitrogen/generated/android/c++/JNitroRow.hpp +33 -3
- package/nitrogen/generated/android/c++/JNitroSection.hpp +6 -0
- package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +6 -0
- package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ChargingConnector.kt +30 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridImageSize.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridTemplateConfig.kt +9 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +5 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ListImageType.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerLocation.kt +90 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerOutlet.kt +70 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelChargerSection.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelConfig.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelGridSection.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelSection.kt +75 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRow.kt +36 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/WaypointCoordinate.kt +61 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +174 -0
- package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +27 -0
- package/nitrogen/generated/ios/c++/HybridGridTemplateSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridInformationTemplateSpecSwift.hpp +9 -0
- package/nitrogen/generated/ios/c++/HybridListTemplateSpecSwift.hpp +9 -0
- package/nitrogen/generated/ios/c++/HybridMapTemplateSpecSwift.hpp +47 -1
- package/nitrogen/generated/ios/c++/HybridSearchTemplateSpecSwift.hpp +9 -0
- package/nitrogen/generated/ios/swift/ChargingConnector.swift +68 -0
- package/nitrogen/generated/ios/swift/GridImageSize.swift +48 -0
- package/nitrogen/generated/ios/swift/GridTemplateConfig.swift +12 -1
- package/nitrogen/generated/ios/swift/HybridMapTemplateSpec.swift +2 -1
- package/nitrogen/generated/ios/swift/HybridMapTemplateSpec_cxx.swift +31 -4
- package/nitrogen/generated/ios/swift/ListImageType.swift +52 -0
- package/nitrogen/generated/ios/swift/NitroChargerLocation.swift +161 -0
- package/nitrogen/generated/ios/swift/NitroChargerOutlet.swift +65 -0
- package/nitrogen/generated/ios/swift/NitroOptionsPanelChargerSection.swift +64 -0
- package/nitrogen/generated/ios/swift/NitroOptionsPanelConfig.swift +94 -0
- package/nitrogen/generated/ios/swift/NitroOptionsPanelGridSection.swift +53 -0
- package/nitrogen/generated/ios/swift/NitroOptionsPanelSection.swift +32 -0
- package/nitrogen/generated/ios/swift/NitroRow.swift +81 -1
- package/nitrogen/generated/ios/swift/WaypointCoordinate.swift +52 -0
- package/nitrogen/generated/shared/c++/ChargingConnector.hpp +104 -0
- package/nitrogen/generated/shared/c++/GridImageSize.hpp +84 -0
- package/nitrogen/generated/shared/c++/GridTemplateConfig.hpp +8 -1
- package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.hpp +5 -1
- package/nitrogen/generated/shared/c++/ListImageType.hpp +88 -0
- package/nitrogen/generated/shared/c++/NitroChargerLocation.hpp +131 -0
- package/nitrogen/generated/shared/c++/NitroChargerOutlet.hpp +98 -0
- package/nitrogen/generated/shared/c++/NitroOptionsPanelChargerSection.hpp +98 -0
- package/nitrogen/generated/shared/c++/NitroOptionsPanelConfig.hpp +107 -0
- package/nitrogen/generated/shared/c++/NitroOptionsPanelGridSection.hpp +91 -0
- package/nitrogen/generated/shared/c++/NitroRow.hpp +39 -2
- package/nitrogen/generated/shared/c++/WaypointCoordinate.hpp +91 -0
- package/package.json +1 -1
- package/src/Constants.ts +9 -0
- package/src/index.ts +1 -0
- package/src/specs/MapTemplate.nitro.ts +3 -1
- package/src/templates/GridTemplate.ts +38 -3
- package/src/templates/InformationTemplate.ts +60 -29
- package/src/templates/ListTemplate.ts +27 -55
- package/src/templates/MapTemplate.ts +60 -2
- package/src/templates/MessageTemplate.ts +71 -24
- package/src/utils/NitroOptionsPanel.ts +218 -0
- package/src/utils/NitroSection.ts +160 -5
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
AutoImage,
|
|
6
6
|
BaseMapTemplateConfig,
|
|
7
7
|
CustomActionButtonAndroid,
|
|
8
|
-
|
|
8
|
+
HeaderActions,
|
|
9
9
|
TextButton,
|
|
10
10
|
} from '..';
|
|
11
11
|
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
@@ -14,6 +14,7 @@ import type { AutoText } from '../types/Text';
|
|
|
14
14
|
import { type NitroAction, NitroActionUtil } from '../utils/NitroAction';
|
|
15
15
|
import { type NitroImage, NitroImageUtil } from '../utils/NitroImage';
|
|
16
16
|
import { NitroMapButton } from '../utils/NitroMapButton';
|
|
17
|
+
import type { PanelActionsIos, PanelHeaderActions } from './MapTemplate';
|
|
17
18
|
import type { NitroBaseMapTemplateConfig, NitroTemplateConfig, TemplateConfig } from './Template';
|
|
18
19
|
|
|
19
20
|
const HybridMessageTemplate =
|
|
@@ -23,6 +24,7 @@ export interface NitroMessageTemplateConfig extends TemplateConfig {
|
|
|
23
24
|
headerActions?: Array<NitroAction>;
|
|
24
25
|
/**
|
|
25
26
|
* @namespace Android title shown on header
|
|
27
|
+
* @namespace iOS title shown when mapConfig is set, otherwise it isn't supported
|
|
26
28
|
*/
|
|
27
29
|
title?: AutoText;
|
|
28
30
|
message: AutoText;
|
|
@@ -31,41 +33,86 @@ export interface NitroMessageTemplateConfig extends TemplateConfig {
|
|
|
31
33
|
mapConfig?: NitroBaseMapTemplateConfig;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
type MessageActionsAndroid<T> =
|
|
37
|
+
| [CustomActionButtonAndroid<T>]
|
|
38
|
+
| [CustomActionButtonAndroid<T>, CustomActionButtonAndroid<T>];
|
|
39
|
+
|
|
40
|
+
type MessageTemplateBaseConfig = Omit<
|
|
35
41
|
NitroMessageTemplateConfig,
|
|
36
42
|
'headerActions' | 'image' | 'mapConfig' | 'actions'
|
|
37
43
|
> & {
|
|
38
44
|
/**
|
|
39
45
|
* action buttons, usually at the top right on Android
|
|
40
|
-
* @namespace
|
|
46
|
+
* @namespace iOS `ios` only takes effect once this renders as a CPMapPanel (`mapConfig` set,
|
|
47
|
+
* iOS 27+) and is applied to the root map template's nav bar — without `mapConfig` (or below
|
|
48
|
+
* iOS 27, where `mapConfig` is a no-op) this template is a full-screen `CPAlertTemplate`, which
|
|
49
|
+
* has no nav bar at all, so `ios` is silently unused there.
|
|
41
50
|
*/
|
|
42
|
-
headerActions?:
|
|
51
|
+
headerActions?: HeaderActions<MessageTemplate>;
|
|
43
52
|
/**
|
|
44
53
|
* image shown at the top of the message on Android
|
|
45
54
|
* @namespace Android
|
|
46
55
|
*/
|
|
47
56
|
image?: AutoImage;
|
|
48
|
-
/**
|
|
49
|
-
* If mapConfig is defined, it will use a MapWithContentTemplate with the current template. This results in a MessageTemplate with a map in background. No actions need to be specified, can be empty object.
|
|
50
|
-
* @namespace Android
|
|
51
|
-
*/
|
|
52
|
-
mapConfig?: BaseMapTemplateConfig<MessageTemplate>;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @namespace Android up to 2 buttons of type TextButton, TextAndImageButton or ImageButton
|
|
56
|
-
* @namespace iOS - up to 3 buttons of type TextButton
|
|
57
|
-
*/
|
|
58
|
-
actions?: {
|
|
59
|
-
android?:
|
|
60
|
-
| [CustomActionButtonAndroid<MessageTemplate>]
|
|
61
|
-
| [CustomActionButtonAndroid<MessageTemplate>, CustomActionButtonAndroid<MessageTemplate>];
|
|
62
|
-
ios?:
|
|
63
|
-
| [TextButton<MessageTemplate>, TextButton<MessageTemplate>, TextButton<MessageTemplate>]
|
|
64
|
-
| [TextButton<MessageTemplate>, TextButton<MessageTemplate>]
|
|
65
|
-
| [TextButton<MessageTemplate>];
|
|
66
|
-
};
|
|
67
57
|
};
|
|
68
58
|
|
|
59
|
+
/**
|
|
60
|
+
* `actions`/`mapConfig` are a discriminated union — `mapConfig` restricts `actions.ios` to at
|
|
61
|
+
* most one `TextButton` plus one icon-only `ImageButton` (a `CPMapPanel` can't show more), vs. up
|
|
62
|
+
* to three `TextButton`s otherwise. If your `mapConfig` value comes from a variable/prop rather
|
|
63
|
+
* than an inline literal, TS can't narrow which branch applies — assign it to a local `const` and
|
|
64
|
+
* branch with `if (mapConfig) { ... } else { ... }` into two separate constructor calls instead
|
|
65
|
+
* of passing it straight through to one.
|
|
66
|
+
*/
|
|
67
|
+
export type MessageTemplateConfig = MessageTemplateBaseConfig &
|
|
68
|
+
(
|
|
69
|
+
| {
|
|
70
|
+
mapConfig?: undefined;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @namespace Android up to 2 buttons of type TextButton, TextAndImageButton or ImageButton
|
|
74
|
+
* @namespace iOS - up to 3 buttons of type TextButton
|
|
75
|
+
*/
|
|
76
|
+
actions?: {
|
|
77
|
+
android?: MessageActionsAndroid<MessageTemplate>;
|
|
78
|
+
ios?:
|
|
79
|
+
| [
|
|
80
|
+
TextButton<MessageTemplate>,
|
|
81
|
+
TextButton<MessageTemplate>,
|
|
82
|
+
TextButton<MessageTemplate>,
|
|
83
|
+
]
|
|
84
|
+
| [TextButton<MessageTemplate>, TextButton<MessageTemplate>]
|
|
85
|
+
| [TextButton<MessageTemplate>];
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
| {
|
|
89
|
+
/**
|
|
90
|
+
* If mapConfig is defined, it will use a MapWithContentTemplate with the current
|
|
91
|
+
* template. This results in a MessageTemplate with a map in background. No actions
|
|
92
|
+
* need to be specified, can be empty object.
|
|
93
|
+
* @namespace Android - uses MapWithContentTemplate
|
|
94
|
+
* @namespace iOS - renders as a CPMapPanel on the current root map template (iOS 27+),
|
|
95
|
+
* trading the usual full-screen modal alert presentation for panel content;
|
|
96
|
+
* `headerActions` here is Android-only — on iOS this template's own `headerActions` are
|
|
97
|
+
* applied to the root map template's nav bar instead, since CarPlay has no separate
|
|
98
|
+
* header for the map behind a panel.
|
|
99
|
+
*/
|
|
100
|
+
mapConfig: Omit<BaseMapTemplateConfig<MessageTemplate>, 'headerActions'> & {
|
|
101
|
+
headerActions?: PanelHeaderActions<MessageTemplate>;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @namespace Android up to 2 buttons of type TextButton, TextAndImageButton or ImageButton
|
|
106
|
+
* @namespace iOS - the panel can only show one TextButton plus one optional icon-only
|
|
107
|
+
* ImageButton, see PanelActionsIos
|
|
108
|
+
*/
|
|
109
|
+
actions?: {
|
|
110
|
+
android?: MessageActionsAndroid<MessageTemplate>;
|
|
111
|
+
ios?: PanelActionsIos<MessageTemplate>;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
69
116
|
/**
|
|
70
117
|
* This template is always pushed on top and will stay on top until it is popped.
|
|
71
118
|
* Other templates being pushed will end up below this one on the stack.
|
|
@@ -86,7 +133,7 @@ export class MessageTemplate {
|
|
|
86
133
|
const nitroConfig: NitroMessageTemplateConfig & NitroTemplateConfig = {
|
|
87
134
|
...rest,
|
|
88
135
|
id: this.id,
|
|
89
|
-
headerActions: NitroActionUtil.convert(this.template,
|
|
136
|
+
headerActions: NitroActionUtil.convert(this.template, headerActions),
|
|
90
137
|
image: NitroImageUtil.convert(image),
|
|
91
138
|
actions: platformActions,
|
|
92
139
|
mapConfig: mapConfig
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { ImageButton, TextButton } from '../types/Button';
|
|
2
|
+
import type { AutoImage } from '../types/Image';
|
|
3
|
+
import type { AutoText, Distance } from '../types/Text';
|
|
4
|
+
import type { DurationWithTimeZone } from '../types/Trip';
|
|
5
|
+
import { type NitroAction, NitroActionUtil } from './NitroAction';
|
|
6
|
+
import { type GridButton, type NitroGridButton, NitroGridUtil } from './NitroGrid';
|
|
7
|
+
import { type NitroImage, NitroImageUtil } from './NitroImage';
|
|
8
|
+
import {
|
|
9
|
+
type DefaultRow,
|
|
10
|
+
type MultiSection,
|
|
11
|
+
type NitroSection,
|
|
12
|
+
NitroSectionUtil,
|
|
13
|
+
type RadioRow,
|
|
14
|
+
type TextRow,
|
|
15
|
+
type ToggleRow,
|
|
16
|
+
type WaypointCoordinate,
|
|
17
|
+
type WaypointRow,
|
|
18
|
+
} from './NitroSection';
|
|
19
|
+
|
|
20
|
+
export type OptionsPanelGridSection<T> = {
|
|
21
|
+
type: 'grid';
|
|
22
|
+
title?: string;
|
|
23
|
+
buttons: Array<GridButton<T>>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ChargingConnector =
|
|
27
|
+
| 'ccs1'
|
|
28
|
+
| 'ccs2'
|
|
29
|
+
| 'j1772'
|
|
30
|
+
| 'chaDeMo'
|
|
31
|
+
| 'mennekes'
|
|
32
|
+
| 'gbtDC'
|
|
33
|
+
| 'gbtAC'
|
|
34
|
+
| 'nacsDC'
|
|
35
|
+
| 'nacsAC';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* one outlet (`CPChargingStationConnection`) on a charging station.
|
|
39
|
+
*/
|
|
40
|
+
export type ChargerOutlet<T> = {
|
|
41
|
+
connector: ChargingConnector;
|
|
42
|
+
voltage: number;
|
|
43
|
+
/** converted to megawatts on the native side above 1000 kW */
|
|
44
|
+
powerKw: number;
|
|
45
|
+
onPress?: (template: T) => void;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* the charging station's own location, shown as an additional `CPMapTemplateWaypoint` item in
|
|
50
|
+
* the charger section, alongside its outlets.
|
|
51
|
+
*/
|
|
52
|
+
export type ChargerLocation<T> = {
|
|
53
|
+
/**
|
|
54
|
+
* the item's own label — distinct from the section's `title`, which is already shown as the
|
|
55
|
+
* section header, so this defaults to blank rather than repeating it.
|
|
56
|
+
*/
|
|
57
|
+
name?: string;
|
|
58
|
+
/** newline-separated address lines, most-preferred first */
|
|
59
|
+
address?: string;
|
|
60
|
+
coordinate: WaypointCoordinate;
|
|
61
|
+
travelEstimates: {
|
|
62
|
+
distance: Distance;
|
|
63
|
+
duration: DurationWithTimeZone;
|
|
64
|
+
/**
|
|
65
|
+
* by default travel estimates are not shown
|
|
66
|
+
* setting this to true add another row showing CPTravelEstimates
|
|
67
|
+
*/
|
|
68
|
+
visible?: boolean;
|
|
69
|
+
};
|
|
70
|
+
image?: AutoImage;
|
|
71
|
+
onPress?: (template: T) => void;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* charger section having n-ChargerOutlet
|
|
76
|
+
*/
|
|
77
|
+
export type OptionsPanelChargerSection<T> = {
|
|
78
|
+
type: 'charger';
|
|
79
|
+
title?: string;
|
|
80
|
+
outlets: Array<ChargerOutlet<T>>;
|
|
81
|
+
location?: ChargerLocation<T>;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type OptionsPanelListSection<T> = {
|
|
85
|
+
type: 'list';
|
|
86
|
+
title?: string;
|
|
87
|
+
items: Array<DefaultRow<T> | ToggleRow<T> | TextRow | WaypointRow<T>> | Array<RadioRow<T>>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type OptionsPanelSection<T> =
|
|
91
|
+
| OptionsPanelListSection<T>
|
|
92
|
+
| OptionsPanelGridSection<T>
|
|
93
|
+
| OptionsPanelChargerSection<T>;
|
|
94
|
+
|
|
95
|
+
export type OptionsPanelConfig<T> = {
|
|
96
|
+
title?: AutoText;
|
|
97
|
+
sections: Array<OptionsPanelSection<T>>;
|
|
98
|
+
actions?: [TextButton<T>] | [TextButton<T>, ImageButton<T>];
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type NitroOptionsPanelGridSection = {
|
|
102
|
+
title?: string;
|
|
103
|
+
buttons: Array<NitroGridButton>;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type NitroChargerOutlet = {
|
|
107
|
+
connector: ChargingConnector;
|
|
108
|
+
voltage: number;
|
|
109
|
+
powerKw: number;
|
|
110
|
+
onPress?: () => void;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export type NitroChargerLocation = {
|
|
114
|
+
name?: string;
|
|
115
|
+
address?: string;
|
|
116
|
+
coordinate: WaypointCoordinate;
|
|
117
|
+
distance: Distance;
|
|
118
|
+
duration: DurationWithTimeZone;
|
|
119
|
+
visible?: boolean;
|
|
120
|
+
image?: NitroImage;
|
|
121
|
+
onPress?: () => void;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export type NitroOptionsPanelChargerSection = {
|
|
125
|
+
title?: string;
|
|
126
|
+
outlets: Array<NitroChargerOutlet>;
|
|
127
|
+
location?: NitroChargerLocation;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export type NitroOptionsPanelSection =
|
|
131
|
+
| NitroSection
|
|
132
|
+
| NitroOptionsPanelGridSection
|
|
133
|
+
| NitroOptionsPanelChargerSection;
|
|
134
|
+
|
|
135
|
+
export type NitroOptionsPanelConfig = {
|
|
136
|
+
title?: AutoText;
|
|
137
|
+
sections: Array<NitroOptionsPanelSection>;
|
|
138
|
+
actions?: Array<NitroAction>;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const isRadioSection = <T>(
|
|
142
|
+
items: OptionsPanelListSection<T>['items']
|
|
143
|
+
): items is Array<RadioRow<T>> => {
|
|
144
|
+
return items.length > 0 && items.every((item) => item.type === 'radio');
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const convertSection = <T>(
|
|
148
|
+
template: T,
|
|
149
|
+
section: OptionsPanelSection<T>
|
|
150
|
+
): NitroOptionsPanelSection => {
|
|
151
|
+
if (section.type === 'grid') {
|
|
152
|
+
return {
|
|
153
|
+
title: section.title,
|
|
154
|
+
buttons: NitroGridUtil.convert(template, section.buttons),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (section.type === 'charger') {
|
|
159
|
+
const { location } = section;
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
title: section.title,
|
|
163
|
+
outlets: section.outlets.map((outlet) => ({
|
|
164
|
+
connector: outlet.connector,
|
|
165
|
+
voltage: outlet.voltage,
|
|
166
|
+
powerKw: outlet.powerKw,
|
|
167
|
+
onPress: outlet.onPress ? () => outlet.onPress?.(template) : undefined,
|
|
168
|
+
})),
|
|
169
|
+
location: location
|
|
170
|
+
? {
|
|
171
|
+
name: location.name,
|
|
172
|
+
address: location.address,
|
|
173
|
+
coordinate: location.coordinate,
|
|
174
|
+
distance: location.travelEstimates.distance,
|
|
175
|
+
duration: location.travelEstimates.duration,
|
|
176
|
+
visible: location.travelEstimates.visible,
|
|
177
|
+
image: NitroImageUtil.convert(location.image),
|
|
178
|
+
onPress: location.onPress ? () => location.onPress?.(template) : undefined,
|
|
179
|
+
}
|
|
180
|
+
: undefined,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const { items, title = '' } = section;
|
|
185
|
+
|
|
186
|
+
const multiSection: MultiSection<T> = isRadioSection(items)
|
|
187
|
+
? { type: 'radio', title, items }
|
|
188
|
+
: {
|
|
189
|
+
type: 'default',
|
|
190
|
+
title,
|
|
191
|
+
items,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const [nitroSection] = NitroSectionUtil.convert(template, [multiSection]) ?? [];
|
|
195
|
+
|
|
196
|
+
if (nitroSection == null) {
|
|
197
|
+
throw new Error('converting sections failed');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return nitroSection;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const convert = <T>(
|
|
204
|
+
template: T,
|
|
205
|
+
config?: OptionsPanelConfig<T>
|
|
206
|
+
): NitroOptionsPanelConfig | undefined => {
|
|
207
|
+
if (config == null) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
title: config.title,
|
|
213
|
+
sections: config.sections.map((section) => convertSection(template, section)),
|
|
214
|
+
actions: NitroActionUtil.convert(template, config.actions),
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export const NitroOptionsPanelUtil = { convert };
|
|
@@ -1,7 +1,95 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { ListImageType } from '../templates/ListTemplate';
|
|
2
|
+
import type { AutoImage } from '../types/Image';
|
|
3
|
+
import { type AutoText, type Distance, TextPlaceholders } from '../types/Text';
|
|
4
|
+
import type { DurationWithTimeZone } from '../types/Trip';
|
|
3
5
|
import { type NitroImage, NitroImageUtil } from './NitroImage';
|
|
4
6
|
|
|
7
|
+
type BaseRow = {
|
|
8
|
+
title: AutoText;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
image?: AutoImage;
|
|
11
|
+
/** @namespace Android */
|
|
12
|
+
imageType?: ListImageType;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type DefaultRow<T> = BaseRow & {
|
|
16
|
+
type: 'default';
|
|
17
|
+
/**
|
|
18
|
+
* adds a chevron at the end of the row
|
|
19
|
+
*/
|
|
20
|
+
browsable?: boolean;
|
|
21
|
+
onPress: (template: T) => void;
|
|
22
|
+
detailedText?: AutoText;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type ToggleRow<T> = BaseRow & {
|
|
26
|
+
type: 'toggle';
|
|
27
|
+
checked: boolean;
|
|
28
|
+
onPress: (template: T, checked: boolean) => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type RadioRow<T> = BaseRow & {
|
|
32
|
+
type: 'radio';
|
|
33
|
+
onPress: (template: T) => void;
|
|
34
|
+
selected?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type TextRow = BaseRow & {
|
|
38
|
+
type: 'text';
|
|
39
|
+
detailedText?: AutoText;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type WaypointCoordinate = {
|
|
43
|
+
latitude: number;
|
|
44
|
+
longitude: number;
|
|
45
|
+
altitude?: number;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* a point of interest, e.g. a charger's location. Renders as a `CPMapTemplateWaypoint` item
|
|
50
|
+
* (showing `title` as the name, `address` as the address, and the travel estimate for reaching
|
|
51
|
+
* it) when part of a `CPMapPanel` (iOS 27+); falls back to a plain row using `title`/`address`
|
|
52
|
+
* as the detail line everywhere else (including Android, which has no equivalent concept).
|
|
53
|
+
*/
|
|
54
|
+
export type WaypointRow<T> = BaseRow & {
|
|
55
|
+
type: 'waypoint';
|
|
56
|
+
/**
|
|
57
|
+
* add one of {@link TextPlaceholders} to add travelEstimates
|
|
58
|
+
* prefer travelEstimates.visible over that on iOS 27+
|
|
59
|
+
*/
|
|
60
|
+
address?: string;
|
|
61
|
+
coordinate: WaypointCoordinate;
|
|
62
|
+
travelEstimates: {
|
|
63
|
+
distance: Distance;
|
|
64
|
+
duration: DurationWithTimeZone;
|
|
65
|
+
/**
|
|
66
|
+
* by default travel estimates are not shown
|
|
67
|
+
* setting this to true adds another row showing CPTravelEstimates
|
|
68
|
+
* @namespace iOS 27+
|
|
69
|
+
*/
|
|
70
|
+
visible?: boolean;
|
|
71
|
+
};
|
|
72
|
+
onPress?: (template: T) => void;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type MultiSection<T> =
|
|
76
|
+
| {
|
|
77
|
+
type: 'default';
|
|
78
|
+
title: string;
|
|
79
|
+
items: Array<DefaultRow<T> | ToggleRow<T> | TextRow | WaypointRow<T>>;
|
|
80
|
+
}
|
|
81
|
+
| {
|
|
82
|
+
type: 'radio';
|
|
83
|
+
title: string;
|
|
84
|
+
items: Array<RadioRow<T>>;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type SingleSection<T> = {
|
|
88
|
+
[K in MultiSection<T> as K['type']]: Omit<K, 'title' | 'detailedText'>;
|
|
89
|
+
}[MultiSection<T>['type']];
|
|
90
|
+
|
|
91
|
+
export type Section<T> = Array<MultiSection<T>> | SingleSection<T>;
|
|
92
|
+
|
|
5
93
|
type NitroSectionType = 'default' | 'radio';
|
|
6
94
|
|
|
7
95
|
export type NitroRow = {
|
|
@@ -10,9 +98,20 @@ export type NitroRow = {
|
|
|
10
98
|
browsable?: boolean;
|
|
11
99
|
enabled: boolean;
|
|
12
100
|
image?: NitroImage;
|
|
101
|
+
imageType?: ListImageType;
|
|
13
102
|
checked?: boolean;
|
|
14
103
|
onPress?: (checked?: boolean) => void;
|
|
15
104
|
selected?: boolean;
|
|
105
|
+
coordinate?: WaypointCoordinate;
|
|
106
|
+
distance?: Distance;
|
|
107
|
+
duration?: DurationWithTimeZone;
|
|
108
|
+
/**
|
|
109
|
+
* only meaningful in panel context (iOS 27+, `mapConfig` set) — adds a sibling `CPMapPanelItem`
|
|
110
|
+
* showing `distance`/`duration` as a native `CPTravelEstimates` row. Non-panel/Android rendering
|
|
111
|
+
* relies purely on `title`/`detailedText` opting in via `TextPlaceholders` instead.
|
|
112
|
+
*/
|
|
113
|
+
travelEstimatesVisible?: boolean;
|
|
114
|
+
address?: string;
|
|
16
115
|
};
|
|
17
116
|
|
|
18
117
|
export type NitroSection = {
|
|
@@ -63,13 +162,63 @@ const convert = <T>(template: T, sections?: Section<T>): Array<NitroSection> | u
|
|
|
63
162
|
];
|
|
64
163
|
};
|
|
65
164
|
|
|
165
|
+
/**
|
|
166
|
+
* `AutoText.distance`/`.duration` only take effect if `text` actually uses the matching
|
|
167
|
+
* `TextPlaceholders` marker — populate whichever of those the text references, leaving the rest
|
|
168
|
+
* of `text` untouched, so a title/address that doesn't opt in via a placeholder is unaffected.
|
|
169
|
+
*/
|
|
170
|
+
const withTravelEstimates = (
|
|
171
|
+
text: AutoText,
|
|
172
|
+
distance: Distance,
|
|
173
|
+
durationSeconds: number
|
|
174
|
+
): AutoText => {
|
|
175
|
+
const hasDistance = text.text.includes(TextPlaceholders.Distance);
|
|
176
|
+
const hasDuration = text.text.includes(TextPlaceholders.Duration);
|
|
177
|
+
|
|
178
|
+
if (!hasDistance && !hasDuration) {
|
|
179
|
+
return text;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
...text,
|
|
184
|
+
distance: hasDistance ? distance : text.distance,
|
|
185
|
+
duration: hasDuration ? durationSeconds : text.duration,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
|
|
66
189
|
const convertRow = <T>(
|
|
67
190
|
template: T,
|
|
68
|
-
item: DefaultRow<T> | RadioRow<T> | ToggleRow<T> | TextRow
|
|
191
|
+
item: DefaultRow<T> | RadioRow<T> | ToggleRow<T> | TextRow | WaypointRow<T>
|
|
69
192
|
): NitroRow => {
|
|
70
|
-
const {
|
|
193
|
+
const { type, enabled = true, image, imageType } = item;
|
|
194
|
+
|
|
195
|
+
// `WaypointRow` has no `detailedText` of its own — `address` doubles as the detail line
|
|
196
|
+
// whenever this falls back to a plain row (non-panel context, Android).
|
|
197
|
+
let title = item.title;
|
|
198
|
+
let detailedText =
|
|
199
|
+
item.type === 'waypoint'
|
|
200
|
+
? item.address != null
|
|
201
|
+
? { text: item.address }
|
|
202
|
+
: undefined
|
|
203
|
+
: 'detailedText' in item
|
|
204
|
+
? item.detailedText
|
|
205
|
+
: undefined;
|
|
206
|
+
|
|
207
|
+
// Opt-in only: a title/address using `{distance}`/`{duration}` gets those values filled in,
|
|
208
|
+
// via the same substitution `AutoText` already does everywhere else — no separate "estimate"
|
|
209
|
+
// UI element needed for a row embedded in a list alongside other rows. Deliberately NOT gated
|
|
210
|
+
// on `travelEstimates.visible` — that flag only controls the panel-only sibling
|
|
211
|
+
// `CPTravelEstimates` item (see `Parser.swift`'s `travelEstimatesVisible` check), which has no
|
|
212
|
+
// bearing on the non-panel/Android fallback text this feeds; a placeholder in the text is
|
|
213
|
+
// already its own explicit opt-in regardless of `visible`.
|
|
214
|
+
if (item.type === 'waypoint') {
|
|
215
|
+
const { distance, duration } = item.travelEstimates;
|
|
216
|
+
title = withTravelEstimates(title, distance, duration.seconds);
|
|
217
|
+
if (detailedText != null) {
|
|
218
|
+
detailedText = withTravelEstimates(detailedText, distance, duration.seconds);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
71
221
|
|
|
72
|
-
const detailedText = 'detailedText' in item ? item.detailedText : undefined;
|
|
73
222
|
const selected = type === 'radio' ? (item.selected ?? false) : undefined;
|
|
74
223
|
|
|
75
224
|
const onTogglePress = item.type === 'toggle' ? item.onPress : undefined;
|
|
@@ -93,10 +242,16 @@ const convertRow = <T>(
|
|
|
93
242
|
detailedText,
|
|
94
243
|
enabled,
|
|
95
244
|
image: NitroImageUtil.convert(image),
|
|
245
|
+
imageType,
|
|
96
246
|
title,
|
|
97
247
|
checked: type === 'toggle' ? item.checked : undefined,
|
|
98
248
|
onPress,
|
|
99
249
|
selected,
|
|
250
|
+
coordinate: item.type === 'waypoint' ? item.coordinate : undefined,
|
|
251
|
+
distance: item.type === 'waypoint' ? item.travelEstimates.distance : undefined,
|
|
252
|
+
duration: item.type === 'waypoint' ? item.travelEstimates.duration : undefined,
|
|
253
|
+
travelEstimatesVisible: item.type === 'waypoint' ? item.travelEstimates.visible : undefined,
|
|
254
|
+
address: item.type === 'waypoint' ? item.address : undefined,
|
|
100
255
|
};
|
|
101
256
|
};
|
|
102
257
|
|