expo-live-activity 0.4.1-alpha1 → 0.4.1
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 +2 -2
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +14 -9
- package/build/index.js.map +1 -1
- package/ios/ExpoLiveActivityModule.swift +6 -2
- package/ios/LiveActivityAttributes.swift +2 -1
- package/ios-files/LiveActivityView.swift +32 -8
- package/ios-files/LiveActivityWidget.swift +2 -1
- package/ios-files/ViewHelpers.swift +2 -7
- package/package.json +1 -1
- package/plugin/build/index.js +1 -1
- package/plugin/src/index.ts +2 -2
- package/src/index.ts +22 -12
package/README.md
CHANGED
|
@@ -153,7 +153,7 @@ The `config` object should include:
|
|
|
153
153
|
timerType?: DynamicIslandTimerType; // "circular" | "digital" - defines timer appearance on the dynamic island
|
|
154
154
|
padding?: Padding // number | {top?: number bottom?: number ...}
|
|
155
155
|
imagePosition?: ImagePosition; // 'left' | 'right';
|
|
156
|
-
imageSize?: ImageSize // '
|
|
156
|
+
imageSize?: ImageSize // 'default' | number (points maxHeight)
|
|
157
157
|
};
|
|
158
158
|
```
|
|
159
159
|
|
|
@@ -186,7 +186,7 @@ const config: LiveActivity.LiveActivityConfig = {
|
|
|
186
186
|
timerType: 'circular',
|
|
187
187
|
padding: { horizontal: 20, top: 16, bottom: 16 },
|
|
188
188
|
imagePosition: 'right',
|
|
189
|
-
imageSize: 'default',
|
|
189
|
+
imageSize: 'default', // or a number e.g. 80 for custom image height
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
const activityId = LiveActivity.startActivity(state, config)
|
package/build/index.d.ts
CHANGED
|
@@ -31,8 +31,9 @@ export type Padding = {
|
|
|
31
31
|
vertical?: number;
|
|
32
32
|
horizontal?: number;
|
|
33
33
|
} | number;
|
|
34
|
-
export type ImagePosition = 'left' | 'right';
|
|
35
|
-
export type
|
|
34
|
+
export type ImagePosition = 'left' | 'right' | 'leftStretch' | 'rightStretch';
|
|
35
|
+
export type ImageAlign = 'top' | 'center' | 'bottom';
|
|
36
|
+
export type ImageSize = number;
|
|
36
37
|
export type LiveActivityConfig = {
|
|
37
38
|
backgroundColor?: string;
|
|
38
39
|
titleColor?: string;
|
|
@@ -43,6 +44,7 @@ export type LiveActivityConfig = {
|
|
|
43
44
|
timerType?: DynamicIslandTimerType;
|
|
44
45
|
padding?: Padding;
|
|
45
46
|
imagePosition?: ImagePosition;
|
|
47
|
+
imageAlign?: ImageAlign;
|
|
46
48
|
imageSize?: ImageSize;
|
|
47
49
|
};
|
|
48
50
|
export type ActivityTokenReceivedEvent = {
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAKrD,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;AAE3B,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,SAAS,CAAA;AAE3D,KAAK,eAAe,GAChB;IACE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB,GACD;IACE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAEL,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,OAAO,GACf;IACE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GACD,MAAM,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -6,21 +6,26 @@ function assertIOS(name) {
|
|
|
6
6
|
console.error(`${name} is only available on iOS`);
|
|
7
7
|
return isIOS;
|
|
8
8
|
}
|
|
9
|
+
function normalizeConfig(config) {
|
|
10
|
+
if (config === undefined)
|
|
11
|
+
return config;
|
|
12
|
+
const { padding, ...base } = config;
|
|
13
|
+
const normalized = { ...base };
|
|
14
|
+
// Normalize padding: keep number in padding, object in paddingDetails
|
|
15
|
+
if (typeof padding === 'number') {
|
|
16
|
+
normalized.padding = padding;
|
|
17
|
+
}
|
|
18
|
+
else if (typeof padding === 'object') {
|
|
19
|
+
normalized.paddingDetails = padding;
|
|
20
|
+
}
|
|
21
|
+
return normalized;
|
|
22
|
+
}
|
|
9
23
|
/**
|
|
10
24
|
* @param {LiveActivityState} state The state for the live activity.
|
|
11
25
|
* @param {LiveActivityConfig} config Live activity config object.
|
|
12
26
|
* @returns {string} The identifier of the started activity or undefined if creating live activity failed.
|
|
13
27
|
*/
|
|
14
28
|
export function startActivity(state, config) {
|
|
15
|
-
function normalizeConfig(config) {
|
|
16
|
-
if (typeof config?.padding === 'number') {
|
|
17
|
-
return { ...config, padding: config.padding, paddingDetails: undefined };
|
|
18
|
-
}
|
|
19
|
-
if (typeof config?.padding === 'object') {
|
|
20
|
-
return { ...config, padding: undefined, paddingDetails: config.padding };
|
|
21
|
-
}
|
|
22
|
-
return config;
|
|
23
|
-
}
|
|
24
29
|
if (assertIOS('startActivity'))
|
|
25
30
|
return ExpoLiveActivityModule.startActivity(state, normalizeConfig(config));
|
|
26
31
|
}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,sBAAsB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,sBAAsB,MAAM,0BAA0B,CAAA;AAwF7D,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAA;IAEnC,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAA;IAE7D,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,eAAe,CAAC,MAA2B;IAClD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IAEvC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IAEnC,MAAM,UAAU,GAAqB,EAAE,GAAG,IAAI,EAAE,CAAA;IAEhD,sEAAsE;IACtE,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAC9B,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvC,UAAU,CAAC,cAAc,GAAG,OAAO,CAAA;IACrC,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAwB,EAAE,MAA2B;IACjF,IAAI,SAAS,CAAC,eAAe,CAAC;QAAE,OAAO,sBAAsB,CAAC,aAAa,CAAC,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;AAC7G,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,KAAwB;IAC/D,IAAI,SAAS,CAAC,cAAc,CAAC;QAAE,OAAO,sBAAsB,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;AACtF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,KAAwB;IACjE,IAAI,SAAS,CAAC,gBAAgB,CAAC;QAAE,OAAO,sBAAsB,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;AAC1F,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,QAAqD;IAErD,IAAI,SAAS,CAAC,0BAA0B,CAAC;QAAE,OAAO,sBAAsB,CAAC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAA;AACnH,CAAC;AAED,MAAM,UAAU,mCAAmC,CACjD,QAAgE;IAEhE,IAAI,SAAS,CAAC,qCAAqC,CAAC;QAClD,OAAO,sBAAsB,CAAC,WAAW,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAA;AACrF,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,QAA8C;IAE9C,IAAI,SAAS,CAAC,4BAA4B,CAAC;QAAE,OAAO,sBAAsB,CAAC,WAAW,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;AACnH,CAAC","sourcesContent":["import { EventSubscription } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport ExpoLiveActivityModule from './ExpoLiveActivityModule'\n\ntype Voidable<T> = T | void\n\nexport type DynamicIslandTimerType = 'circular' | 'digital'\n\ntype ProgressBarType =\n | {\n date?: number\n progress?: undefined\n }\n | {\n date?: undefined\n progress?: number\n }\n\nexport type LiveActivityState = {\n title: string\n subtitle?: string\n progressBar?: ProgressBarType\n imageName?: string\n dynamicIslandImageName?: string\n}\n\nexport type NativeLiveActivityState = {\n title: string\n subtitle?: string\n date?: number\n progress?: number\n imageName?: string\n dynamicIslandImageName?: string\n}\n\nexport type Padding =\n | {\n top?: number\n bottom?: number\n left?: number\n right?: number\n vertical?: number\n horizontal?: number\n }\n | number\n\nexport type ImagePosition = 'left' | 'right' | 'leftStretch' | 'rightStretch'\n\nexport type ImageAlign = 'top' | 'center' | 'bottom'\n\nexport type ImageSize = number\n\nexport type LiveActivityConfig = {\n backgroundColor?: string\n titleColor?: string\n subtitleColor?: string\n progressViewTint?: string\n progressViewLabelColor?: string\n deepLinkUrl?: string\n timerType?: DynamicIslandTimerType\n padding?: Padding\n imagePosition?: ImagePosition\n imageAlign?: ImageAlign\n imageSize?: ImageSize\n}\n\nexport type ActivityTokenReceivedEvent = {\n activityID: string\n activityName: string\n activityPushToken: string\n}\n\nexport type ActivityPushToStartTokenReceivedEvent = {\n activityPushToStartToken: string\n}\n\ntype ActivityState = 'active' | 'dismissed' | 'pending' | 'stale' | 'ended'\n\nexport type ActivityUpdateEvent = {\n activityID: string\n activityName: string\n activityState: ActivityState\n}\n\nexport type LiveActivityModuleEvents = {\n onTokenReceived: (params: ActivityTokenReceivedEvent) => void\n onPushToStartTokenReceived: (params: ActivityPushToStartTokenReceivedEvent) => void\n onStateChange: (params: ActivityUpdateEvent) => void\n}\n\nfunction assertIOS(name: string) {\n const isIOS = Platform.OS === 'ios'\n\n if (!isIOS) console.error(`${name} is only available on iOS`)\n\n return isIOS\n}\n\nfunction normalizeConfig(config?: LiveActivityConfig) {\n if (config === undefined) return config\n\n const { padding, ...base } = config\n type NormalizedConfig = LiveActivityConfig & { paddingDetails?: Padding }\n const normalized: NormalizedConfig = { ...base }\n\n // Normalize padding: keep number in padding, object in paddingDetails\n if (typeof padding === 'number') {\n normalized.padding = padding\n } else if (typeof padding === 'object') {\n normalized.paddingDetails = padding\n }\n\n return normalized\n}\n\n/**\n * @param {LiveActivityState} state The state for the live activity.\n * @param {LiveActivityConfig} config Live activity config object.\n * @returns {string} The identifier of the started activity or undefined if creating live activity failed.\n */\nexport function startActivity(state: LiveActivityState, config?: LiveActivityConfig): Voidable<string> {\n if (assertIOS('startActivity')) return ExpoLiveActivityModule.startActivity(state, normalizeConfig(config))\n}\n\n/**\n * @param {string} id The identifier of the activity to stop.\n * @param {LiveActivityState} state The updated state for the live activity.\n */\nexport function stopActivity(id: string, state: LiveActivityState) {\n if (assertIOS('stopActivity')) return ExpoLiveActivityModule.stopActivity(id, state)\n}\n\n/**\n * @param {string} id The identifier of the activity to update.\n * @param {LiveActivityState} state The updated state for the live activity.\n */\nexport function updateActivity(id: string, state: LiveActivityState) {\n if (assertIOS('updateActivity')) return ExpoLiveActivityModule.updateActivity(id, state)\n}\n\nexport function addActivityTokenListener(\n listener: (event: ActivityTokenReceivedEvent) => void\n): Voidable<EventSubscription> {\n if (assertIOS('addActivityTokenListener')) return ExpoLiveActivityModule.addListener('onTokenReceived', listener)\n}\n\nexport function addActivityPushToStartTokenListener(\n listener: (event: ActivityPushToStartTokenReceivedEvent) => void\n): Voidable<EventSubscription> {\n if (assertIOS('addActivityPushToStartTokenListener'))\n return ExpoLiveActivityModule.addListener('onPushToStartTokenReceived', listener)\n}\n\nexport function addActivityUpdatesListener(\n listener: (event: ActivityUpdateEvent) => void\n): Voidable<EventSubscription> {\n if (assertIOS('addActivityUpdatesListener')) return ExpoLiveActivityModule.addListener('onStateChange', listener)\n}\n"]}
|
|
@@ -59,7 +59,10 @@ public class ExpoLiveActivityModule: Module {
|
|
|
59
59
|
var imagePosition: String?
|
|
60
60
|
|
|
61
61
|
@Field
|
|
62
|
-
var imageSize:
|
|
62
|
+
var imageSize: Int?
|
|
63
|
+
|
|
64
|
+
@Field
|
|
65
|
+
var imageAlign: String?
|
|
63
66
|
|
|
64
67
|
struct PaddingDetails: Record {
|
|
65
68
|
@Field var top: Int?
|
|
@@ -222,7 +225,8 @@ public class ExpoLiveActivityModule: Module {
|
|
|
222
225
|
)
|
|
223
226
|
},
|
|
224
227
|
imagePosition: config.imagePosition,
|
|
225
|
-
imageSize: config.imageSize
|
|
228
|
+
imageSize: config.imageSize,
|
|
229
|
+
imageAlign: config.imageAlign
|
|
226
230
|
)
|
|
227
231
|
|
|
228
232
|
let initialState = LiveActivityAttributes.ContentState(
|
|
@@ -22,7 +22,8 @@ struct LiveActivityAttributes: ActivityAttributes {
|
|
|
22
22
|
var padding: Int?
|
|
23
23
|
var paddingDetails: PaddingDetails?
|
|
24
24
|
var imagePosition: String?
|
|
25
|
-
var imageSize:
|
|
25
|
+
var imageSize: Int?
|
|
26
|
+
var imageAlign: String?
|
|
26
27
|
|
|
27
28
|
enum DynamicIslandTimerType: String, Codable {
|
|
28
29
|
case circular
|
|
@@ -23,6 +23,26 @@ import WidgetKit
|
|
|
23
23
|
attributes.progressViewTint.map { Color(hex: $0) }
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
private var imageAlignment: Alignment {
|
|
27
|
+
switch attributes.imageAlign {
|
|
28
|
+
case "center":
|
|
29
|
+
return .center
|
|
30
|
+
case "bottom":
|
|
31
|
+
return .bottom
|
|
32
|
+
default:
|
|
33
|
+
return .top
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@ViewBuilder
|
|
38
|
+
private func alignedImage(imageName: String) -> some View {
|
|
39
|
+
VStack {
|
|
40
|
+
resizableImage(imageName: imageName)
|
|
41
|
+
.applyImageSize(attributes.imageSize)
|
|
42
|
+
}
|
|
43
|
+
.frame(maxHeight: .infinity, alignment: imageAlignment)
|
|
44
|
+
}
|
|
45
|
+
|
|
26
46
|
var body: some View {
|
|
27
47
|
let defaultPadding = 24
|
|
28
48
|
|
|
@@ -55,11 +75,15 @@ import WidgetKit
|
|
|
55
75
|
)
|
|
56
76
|
|
|
57
77
|
VStack(alignment: .leading) {
|
|
78
|
+
let position = attributes.imagePosition ?? "right"
|
|
79
|
+
let isStretch = position.contains("Stretch")
|
|
80
|
+
let isLeftImage = position.hasPrefix("left")
|
|
81
|
+
let hasImage = contentState.imageName != nil
|
|
82
|
+
let effectiveStretch = isStretch && hasImage
|
|
58
83
|
HStack(alignment: .center) {
|
|
59
|
-
if
|
|
84
|
+
if hasImage, isLeftImage {
|
|
60
85
|
if let imageName = contentState.imageName {
|
|
61
|
-
|
|
62
|
-
.applyImageSize(attributes.imageSize)
|
|
86
|
+
alignedImage(imageName: imageName)
|
|
63
87
|
}
|
|
64
88
|
}
|
|
65
89
|
|
|
@@ -75,7 +99,7 @@ import WidgetKit
|
|
|
75
99
|
.modifier(ConditionalForegroundViewModifier(color: attributes.subtitleColor))
|
|
76
100
|
}
|
|
77
101
|
|
|
78
|
-
if
|
|
102
|
+
if effectiveStretch {
|
|
79
103
|
if let date = contentState.timerEndDateInMilliseconds {
|
|
80
104
|
ProgressView(timerInterval: Date.toTimerInterval(miliseconds: date))
|
|
81
105
|
.tint(progressViewTint)
|
|
@@ -88,16 +112,16 @@ import WidgetKit
|
|
|
88
112
|
}
|
|
89
113
|
}
|
|
90
114
|
|
|
91
|
-
if
|
|
115
|
+
if hasImage, !isLeftImage { // right side (default)
|
|
92
116
|
Spacer()
|
|
93
117
|
if let imageName = contentState.imageName {
|
|
94
|
-
|
|
95
|
-
.applyImageSize(attributes.imageSize)
|
|
118
|
+
alignedImage(imageName: imageName)
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
if
|
|
123
|
+
if !effectiveStretch {
|
|
124
|
+
// Bottom progress (hidden when using Stretch variants where progress is inline)
|
|
101
125
|
if let date = contentState.timerEndDateInMilliseconds {
|
|
102
126
|
ProgressView(timerInterval: Date.toTimerInterval(miliseconds: date))
|
|
103
127
|
.tint(progressViewTint)
|
|
@@ -23,7 +23,8 @@ struct LiveActivityAttributes: ActivityAttributes {
|
|
|
23
23
|
var padding: Int?
|
|
24
24
|
var paddingDetails: PaddingDetails?
|
|
25
25
|
var imagePosition: String?
|
|
26
|
-
var imageSize:
|
|
26
|
+
var imageSize: Int?
|
|
27
|
+
var imageAlign: String?
|
|
27
28
|
|
|
28
29
|
enum DynamicIslandTimerType: String, Codable {
|
|
29
30
|
case circular
|
|
@@ -8,12 +8,7 @@ func resizableImage(imageName: String) -> some View {
|
|
|
8
8
|
|
|
9
9
|
extension View {
|
|
10
10
|
@ViewBuilder
|
|
11
|
-
func applyImageSize(_ size:
|
|
12
|
-
|
|
13
|
-
case "fullHeight":
|
|
14
|
-
frame(maxHeight: .infinity)
|
|
15
|
-
default:
|
|
16
|
-
frame(maxHeight: 64)
|
|
17
|
-
}
|
|
11
|
+
func applyImageSize(_ size: Int?) -> some View {
|
|
12
|
+
frame(maxHeight: CGFloat(size ?? 64))
|
|
18
13
|
}
|
|
19
14
|
}
|
package/package.json
CHANGED
package/plugin/build/index.js
CHANGED
|
@@ -11,7 +11,7 @@ const withWidgetExtensionEntitlements_1 = require("./withWidgetExtensionEntitlem
|
|
|
11
11
|
const withXcode_1 = require("./withXcode");
|
|
12
12
|
const withWidgetsAndLiveActivities = (config, props) => {
|
|
13
13
|
const deploymentTarget = '16.2';
|
|
14
|
-
const targetName =
|
|
14
|
+
const targetName = 'LiveActivity';
|
|
15
15
|
const bundleIdentifier = `${config.ios?.bundleIdentifier}.${targetName}`;
|
|
16
16
|
config.ios = {
|
|
17
17
|
...config.ios,
|
package/plugin/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { withPlugins } from 'expo/config-plugins'
|
|
2
2
|
|
|
3
3
|
import type { LiveActivityConfigPlugin } from './types'
|
|
4
4
|
import { withConfig } from './withConfig'
|
|
@@ -9,7 +9,7 @@ import { withXcode } from './withXcode'
|
|
|
9
9
|
|
|
10
10
|
const withWidgetsAndLiveActivities: LiveActivityConfigPlugin = (config, props) => {
|
|
11
11
|
const deploymentTarget = '16.2'
|
|
12
|
-
const targetName =
|
|
12
|
+
const targetName = 'LiveActivity'
|
|
13
13
|
const bundleIdentifier = `${config.ios?.bundleIdentifier}.${targetName}`
|
|
14
14
|
|
|
15
15
|
config.ios = {
|
package/src/index.ts
CHANGED
|
@@ -45,9 +45,11 @@ export type Padding =
|
|
|
45
45
|
}
|
|
46
46
|
| number
|
|
47
47
|
|
|
48
|
-
export type ImagePosition = 'left' | 'right'
|
|
48
|
+
export type ImagePosition = 'left' | 'right' | 'leftStretch' | 'rightStretch'
|
|
49
49
|
|
|
50
|
-
export type
|
|
50
|
+
export type ImageAlign = 'top' | 'center' | 'bottom'
|
|
51
|
+
|
|
52
|
+
export type ImageSize = number
|
|
51
53
|
|
|
52
54
|
export type LiveActivityConfig = {
|
|
53
55
|
backgroundColor?: string
|
|
@@ -59,6 +61,7 @@ export type LiveActivityConfig = {
|
|
|
59
61
|
timerType?: DynamicIslandTimerType
|
|
60
62
|
padding?: Padding
|
|
61
63
|
imagePosition?: ImagePosition
|
|
64
|
+
imageAlign?: ImageAlign
|
|
62
65
|
imageSize?: ImageSize
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -94,22 +97,29 @@ function assertIOS(name: string) {
|
|
|
94
97
|
return isIOS
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
function normalizeConfig(config?: LiveActivityConfig) {
|
|
101
|
+
if (config === undefined) return config
|
|
102
|
+
|
|
103
|
+
const { padding, ...base } = config
|
|
104
|
+
type NormalizedConfig = LiveActivityConfig & { paddingDetails?: Padding }
|
|
105
|
+
const normalized: NormalizedConfig = { ...base }
|
|
106
|
+
|
|
107
|
+
// Normalize padding: keep number in padding, object in paddingDetails
|
|
108
|
+
if (typeof padding === 'number') {
|
|
109
|
+
normalized.padding = padding
|
|
110
|
+
} else if (typeof padding === 'object') {
|
|
111
|
+
normalized.paddingDetails = padding
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return normalized
|
|
115
|
+
}
|
|
116
|
+
|
|
97
117
|
/**
|
|
98
118
|
* @param {LiveActivityState} state The state for the live activity.
|
|
99
119
|
* @param {LiveActivityConfig} config Live activity config object.
|
|
100
120
|
* @returns {string} The identifier of the started activity or undefined if creating live activity failed.
|
|
101
121
|
*/
|
|
102
122
|
export function startActivity(state: LiveActivityState, config?: LiveActivityConfig): Voidable<string> {
|
|
103
|
-
function normalizeConfig(config?: LiveActivityConfig) {
|
|
104
|
-
if (typeof config?.padding === 'number') {
|
|
105
|
-
return { ...config, padding: config.padding, paddingDetails: undefined }
|
|
106
|
-
}
|
|
107
|
-
if (typeof config?.padding === 'object') {
|
|
108
|
-
return { ...config, padding: undefined, paddingDetails: config.padding }
|
|
109
|
-
}
|
|
110
|
-
return config
|
|
111
|
-
}
|
|
112
|
-
|
|
113
123
|
if (assertIOS('startActivity')) return ExpoLiveActivityModule.startActivity(state, normalizeConfig(config))
|
|
114
124
|
}
|
|
115
125
|
|