expo-live-activity 0.2.0-alpha3 → 0.2.0-alpha4
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 +11 -6
- package/build/index.d.ts +4 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -3
- package/build/index.js.map +1 -1
- package/ios/ExpoLiveActivityModule.swift +15 -10
- package/ios/LiveActivityAttributes.swift +1 -0
- package/ios-files/LiveActivityWidget.swift +11 -6
- package/ios-files/View+applyIfPresent.swift +19 -0
- package/ios-files/View+applyWidgetURL.swift +15 -0
- package/package.json +1 -1
- package/src/index.ts +5 -4
package/README.md
CHANGED
|
@@ -74,8 +74,8 @@ The latter requires adding "App Groups" capability to both "main app" and "live
|
|
|
74
74
|
`expo-live-activity` module exports three primary functions to manage live activities:
|
|
75
75
|
|
|
76
76
|
### Managing Live Activities
|
|
77
|
-
- **`startActivity(state: LiveActivityState,
|
|
78
|
-
Start a new live activity. Takes a `state` configuration object for initial activity state and an optional `
|
|
77
|
+
- **`startActivity(state: LiveActivityState, config?: LiveActivityConfig)`**:
|
|
78
|
+
Start a new live activity. Takes a `state` configuration object for initial activity state and an optional `config` object to customize appearance or behavior. It returns the `ID` of the created live activity, which should be stored for future reference.
|
|
79
79
|
|
|
80
80
|
- **`updateActivity(id: string, state: LiveActivityState)`**:
|
|
81
81
|
Update an existing live activity. The `state` object should contain updated information. The `activityId` indicates which activity should be updated.
|
|
@@ -87,6 +87,9 @@ The latter requires adding "App Groups" capability to both "main app" and "live
|
|
|
87
87
|
- **`addActivityTokenListener(listener: (event: ActivityTokenReceivedEvent) => void): EventSubscription)`**:
|
|
88
88
|
Subscribe to changes in the push notification token associated with live activities.
|
|
89
89
|
|
|
90
|
+
### Deep linking
|
|
91
|
+
When starting a new live activity, it's possible to pass `deepLinkUrl` field in `config` object. This can be any string that you can handle in your main app target.
|
|
92
|
+
|
|
90
93
|
### State Object Structure
|
|
91
94
|
The `state` object should include:
|
|
92
95
|
```javascript
|
|
@@ -99,8 +102,8 @@ The `state` object should include:
|
|
|
99
102
|
};
|
|
100
103
|
```
|
|
101
104
|
|
|
102
|
-
###
|
|
103
|
-
The `
|
|
105
|
+
### Config Object Structure
|
|
106
|
+
The `config` object should include:
|
|
104
107
|
```typescript
|
|
105
108
|
{
|
|
106
109
|
backgroundColor?: string;
|
|
@@ -108,6 +111,7 @@ The `styles` object should include:
|
|
|
108
111
|
subtitleColor?: string;
|
|
109
112
|
progressViewTint?: string;
|
|
110
113
|
progressViewLabelColor?: string;
|
|
114
|
+
deepLinkUrl?: string;
|
|
111
115
|
timerType?: DynamicIslandTimerType; // "circular" | "digital" - defines timer appereance on the dynamic island
|
|
112
116
|
};
|
|
113
117
|
```
|
|
@@ -123,16 +127,17 @@ const state = {
|
|
|
123
127
|
dynamicIslandImageName: "dynamic_island_image"
|
|
124
128
|
};
|
|
125
129
|
|
|
126
|
-
const
|
|
130
|
+
const config = {
|
|
127
131
|
backgroundColor: "#FFFFFF",
|
|
128
132
|
titleColor: "#000000",
|
|
129
133
|
subtitleColor: "#333333",
|
|
130
134
|
progressViewTint: "#4CAF50",
|
|
131
135
|
progressViewLabelColor: "#FFFFFF",
|
|
136
|
+
deepLinkUrl: "/dashboard",
|
|
132
137
|
timerType: "circular"
|
|
133
138
|
};
|
|
134
139
|
|
|
135
|
-
const activityId = LiveActivity.startActivity(state,
|
|
140
|
+
const activityId = LiveActivity.startActivity(state, config);
|
|
136
141
|
// Store activityId for future reference
|
|
137
142
|
```
|
|
138
143
|
This will initiate a live activity with the specified title, subtitle, image from your configured assets folder and a time to which there will be a countdown in a progress view.
|
package/build/index.d.ts
CHANGED
|
@@ -7,12 +7,13 @@ export type LiveActivityState = {
|
|
|
7
7
|
imageName?: string;
|
|
8
8
|
dynamicIslandImageName?: string;
|
|
9
9
|
};
|
|
10
|
-
export type
|
|
10
|
+
export type LiveActivityConfig = {
|
|
11
11
|
backgroundColor?: string;
|
|
12
12
|
titleColor?: string;
|
|
13
13
|
subtitleColor?: string;
|
|
14
14
|
progressViewTint?: string;
|
|
15
15
|
progressViewLabelColor?: string;
|
|
16
|
+
deepLinkUrl?: string;
|
|
16
17
|
timerType?: DynamicIslandTimerType;
|
|
17
18
|
};
|
|
18
19
|
export type ActivityTokenReceivedEvent = {
|
|
@@ -24,11 +25,11 @@ export type LiveActivityModuleEvents = {
|
|
|
24
25
|
};
|
|
25
26
|
/**
|
|
26
27
|
* @param {LiveActivityState} state The state for the live activity.
|
|
27
|
-
* @param {
|
|
28
|
+
* @param {LiveActivityConfig} config Live activity config object.
|
|
28
29
|
* @returns {string} The identifier of the started activity.
|
|
29
30
|
* @throws {Error} When function is called on a platform different from iOS.
|
|
30
31
|
*/
|
|
31
|
-
export declare function startActivity(state: LiveActivityState,
|
|
32
|
+
export declare function startActivity(state: LiveActivityState, config?: LiveActivityConfig): string;
|
|
32
33
|
/**
|
|
33
34
|
* @param {string} id The identifier of the activity to stop.
|
|
34
35
|
* @param {LiveActivityState} state The updated state for the live activity.
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,SAAS,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,eAAe,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC;CAC/D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAK3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,OAKhE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,OAKlE;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,GAAG,iBAAiB,CAKjH"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,SAAS,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,eAAe,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC;CAC/D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAK3F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,OAKhE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,OAKlE;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,GAAG,iBAAiB,CAKjH"}
|
package/build/index.js
CHANGED
|
@@ -2,15 +2,15 @@ import ExpoLiveActivityModule from "./ExpoLiveActivityModule";
|
|
|
2
2
|
import { Platform } from "react-native";
|
|
3
3
|
/**
|
|
4
4
|
* @param {LiveActivityState} state The state for the live activity.
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {LiveActivityConfig} config Live activity config object.
|
|
6
6
|
* @returns {string} The identifier of the started activity.
|
|
7
7
|
* @throws {Error} When function is called on a platform different from iOS.
|
|
8
8
|
*/
|
|
9
|
-
export function startActivity(state,
|
|
9
|
+
export function startActivity(state, config) {
|
|
10
10
|
if (Platform.OS !== "ios") {
|
|
11
11
|
throw new Error("startActivity is only available on iOS");
|
|
12
12
|
}
|
|
13
|
-
return ExpoLiveActivityModule.startActivity(state,
|
|
13
|
+
return ExpoLiveActivityModule.startActivity(state, config);
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* @param {string} id The identifier of the activity to stop.
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAgCxC;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAwB,EAAE,MAA2B;IACjF,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,sBAAsB,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,KAAwB;IAC/D,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,sBAAsB,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,KAAwB;IACjE,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,sBAAsB,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,QAAqD;IAC5F,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,sBAAsB,CAAC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC","sourcesContent":["import ExpoLiveActivityModule from \"./ExpoLiveActivityModule\";\nimport { Platform } from \"react-native\";\nimport { EventSubscription } from 'expo-modules-core';\n\nexport type DynamicIslandTimerType = 'circular' | 'digital'\n\nexport type LiveActivityState = {\n title: string;\n subtitle?: string;\n date?: number;\n imageName?: string;\n dynamicIslandImageName?: string;\n};\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};\n\nexport type ActivityTokenReceivedEvent = {\n activityID: string;\n activityPushToken: string;\n};\n\nexport type LiveActivityModuleEvents = {\n onTokenReceived: (params: ActivityTokenReceivedEvent) => void;\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.\n * @throws {Error} When function is called on a platform different from iOS.\n */\nexport function startActivity(state: LiveActivityState, config?: LiveActivityConfig): string {\n if (Platform.OS !== \"ios\") {\n throw new Error(\"startActivity is only available on iOS\");\n }\n return ExpoLiveActivityModule.startActivity(state, 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 * @throws {Error} When function is called on a platform different from iOS.\n */\nexport function stopActivity(id: string, state: LiveActivityState) {\n if (Platform.OS !== \"ios\") {\n throw new Error(\"stopActivity is only available on iOS\");\n }\n 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 * @throws {Error} When function is called on a platform different from iOS.\n */\nexport function updateActivity(id: string, state: LiveActivityState) {\n if (Platform.OS !== \"ios\") {\n throw new Error(\"updateActivity is only available on iOS\");\n }\n return ExpoLiveActivityModule.updateActivity(id, state);\n}\n\nexport function addActivityTokenListener(listener: (event: ActivityTokenReceivedEvent) => void): EventSubscription {\n if (Platform.OS !== \"ios\") {\n throw new Error(\"updateActivity is only available on iOS\");\n }\n return ExpoLiveActivityModule.addListener('onTokenReceived', listener);\n}\n"]}
|
|
@@ -24,7 +24,7 @@ public class ExpoLiveActivityModule: Module {
|
|
|
24
24
|
var dynamicIslandImageName: String?
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
struct
|
|
27
|
+
struct LiveActivityConfig: Record {
|
|
28
28
|
@Field
|
|
29
29
|
var backgroundColor: String?
|
|
30
30
|
|
|
@@ -39,6 +39,9 @@ public class ExpoLiveActivityModule: Module {
|
|
|
39
39
|
|
|
40
40
|
@Field
|
|
41
41
|
var progressViewLabelColor: String?
|
|
42
|
+
|
|
43
|
+
@Field
|
|
44
|
+
var deepLinkUrl: String?
|
|
42
45
|
|
|
43
46
|
@Field
|
|
44
47
|
var timerType: DynamicIslandTimerType?
|
|
@@ -80,19 +83,21 @@ public class ExpoLiveActivityModule: Module {
|
|
|
80
83
|
|
|
81
84
|
Events("onTokenReceived")
|
|
82
85
|
|
|
83
|
-
Function("startActivity") { (state: LiveActivityState,
|
|
86
|
+
Function("startActivity") { (state: LiveActivityState, maybeConfig: LiveActivityConfig?) -> String in
|
|
84
87
|
print("Starting activity")
|
|
85
88
|
if #available(iOS 16.2, *) {
|
|
86
89
|
if ActivityAuthorizationInfo().areActivitiesEnabled {
|
|
87
90
|
do {
|
|
91
|
+
let config = maybeConfig ?? LiveActivityConfig()
|
|
88
92
|
let attributes = LiveActivityAttributes(
|
|
89
93
|
name: "ExpoLiveActivity",
|
|
90
|
-
backgroundColor:
|
|
91
|
-
titleColor:
|
|
92
|
-
subtitleColor:
|
|
93
|
-
progressViewTint:
|
|
94
|
-
progressViewLabelColor:
|
|
95
|
-
|
|
94
|
+
backgroundColor: config.backgroundColor,
|
|
95
|
+
titleColor: config.titleColor,
|
|
96
|
+
subtitleColor: config.subtitleColor,
|
|
97
|
+
progressViewTint: config.progressViewTint,
|
|
98
|
+
progressViewLabelColor: config.progressViewLabelColor,
|
|
99
|
+
deepLinkUrl: config.deepLinkUrl,
|
|
100
|
+
timerType: config.timerType == .digital ? .digital : .circular
|
|
96
101
|
)
|
|
97
102
|
let initialState = LiveActivityAttributes.ContentState(
|
|
98
103
|
title: state.title,
|
|
@@ -100,11 +105,11 @@ public class ExpoLiveActivityModule: Module {
|
|
|
100
105
|
date: toContentStateDate(date: state.date),
|
|
101
106
|
)
|
|
102
107
|
let pushNotificationsEnabled =
|
|
103
|
-
Bundle.main.object(forInfoDictionaryKey: "ExpoLiveActivity_EnablePushNotifications")
|
|
108
|
+
Bundle.main.object(forInfoDictionaryKey: "ExpoLiveActivity_EnablePushNotifications") as? Bool
|
|
104
109
|
let activity = try Activity.request(
|
|
105
110
|
attributes: attributes,
|
|
106
111
|
content: .init(state: initialState, staleDate: nil),
|
|
107
|
-
pushType: pushNotificationsEnabled ==
|
|
112
|
+
pushType: pushNotificationsEnabled == true ? .token : nil
|
|
108
113
|
)
|
|
109
114
|
|
|
110
115
|
Task {
|
|
@@ -23,6 +23,7 @@ struct LiveActivityAttributes: ActivityAttributes {
|
|
|
23
23
|
var subtitleColor: String?
|
|
24
24
|
var progressViewTint: String?
|
|
25
25
|
var progressViewLabelColor: String?
|
|
26
|
+
var deepLinkUrl: String?
|
|
26
27
|
var timerType: DynamicIslandTimerType
|
|
27
28
|
|
|
28
29
|
enum DynamicIslandTimerType: String, Codable {
|
|
@@ -24,6 +24,7 @@ struct LiveActivityAttributes: ActivityAttributes {
|
|
|
24
24
|
var subtitleColor: String?
|
|
25
25
|
var progressViewTint: String?
|
|
26
26
|
var progressViewLabelColor: String?
|
|
27
|
+
var deepLinkUrl: String?
|
|
27
28
|
var timerType: DynamicIslandTimerType
|
|
28
29
|
|
|
29
30
|
enum DynamicIslandTimerType: String, Codable {
|
|
@@ -37,33 +38,37 @@ struct LiveActivityWidget: Widget {
|
|
|
37
38
|
ActivityConfiguration(for: LiveActivityAttributes.self) { context in
|
|
38
39
|
LiveActivityView(contentState: context.state, attributes: context.attributes)
|
|
39
40
|
.activityBackgroundTint(
|
|
40
|
-
context.attributes.backgroundColor
|
|
41
|
+
context.attributes.backgroundColor.map { Color(hex: $0) }
|
|
41
42
|
)
|
|
42
43
|
.activitySystemActionForegroundColor(Color.black)
|
|
43
|
-
|
|
44
|
+
.applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
44
45
|
} dynamicIsland: { context in
|
|
45
46
|
DynamicIsland {
|
|
46
47
|
DynamicIslandExpandedRegion(.leading, priority: 1) {
|
|
47
48
|
dynamicIslandExpandedLeading(title: context.state.title, subtitle: context.state.subtitle)
|
|
48
49
|
.dynamicIsland(verticalPlacement: .belowIfTooWide)
|
|
49
50
|
.padding(.leading, 5)
|
|
51
|
+
.applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
50
52
|
}
|
|
51
53
|
DynamicIslandExpandedRegion(.trailing) {
|
|
52
54
|
if let imageName = context.state.imageName {
|
|
53
55
|
dynamicIslandExpandedTrailing(imageName: imageName)
|
|
54
56
|
.padding(.trailing, 5)
|
|
57
|
+
.applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
DynamicIslandExpandedRegion(.bottom) {
|
|
58
61
|
if let date = context.state.date {
|
|
59
62
|
dynamicIslandExpandedBottom(endDate: date, progressViewTint: context.attributes.progressViewTint)
|
|
60
63
|
.padding(.horizontal, 5)
|
|
64
|
+
.applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
} compactLeading: {
|
|
64
68
|
if let dynamicIslandImageName = context.state.dynamicIslandImageName {
|
|
65
69
|
resizableImage(imageName: dynamicIslandImageName)
|
|
66
70
|
.frame(maxWidth: 23, maxHeight: 23)
|
|
71
|
+
.applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
67
72
|
}
|
|
68
73
|
} compactTrailing: {
|
|
69
74
|
if let date = context.state.date {
|
|
@@ -71,7 +76,7 @@ struct LiveActivityWidget: Widget {
|
|
|
71
76
|
endDate: date,
|
|
72
77
|
timerType: context.attributes.timerType,
|
|
73
78
|
progressViewTint: context.attributes.progressViewTint
|
|
74
|
-
)
|
|
79
|
+
).applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
75
80
|
}
|
|
76
81
|
} minimal: {
|
|
77
82
|
if let date = context.state.date {
|
|
@@ -79,7 +84,7 @@ struct LiveActivityWidget: Widget {
|
|
|
79
84
|
endDate: date,
|
|
80
85
|
timerType: context.attributes.timerType,
|
|
81
86
|
progressViewTint: context.attributes.progressViewTint
|
|
82
|
-
)
|
|
87
|
+
).applyWidgetURL(from: context.attributes.deepLinkUrl)
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
}
|
|
@@ -100,7 +105,7 @@ struct LiveActivityWidget: Widget {
|
|
|
100
105
|
.multilineTextAlignment(.trailing)
|
|
101
106
|
} else {
|
|
102
107
|
circularTimer(endDate: endDate)
|
|
103
|
-
.tint(progressViewTint
|
|
108
|
+
.tint(progressViewTint.map { Color(hex: $0) })
|
|
104
109
|
}
|
|
105
110
|
}
|
|
106
111
|
|
|
@@ -133,7 +138,7 @@ struct LiveActivityWidget: Widget {
|
|
|
133
138
|
private func dynamicIslandExpandedBottom(endDate: Double, progressViewTint: String?) -> some View {
|
|
134
139
|
ProgressView(timerInterval: Date.toTimerInterval(miliseconds: endDate))
|
|
135
140
|
.foregroundStyle(.white)
|
|
136
|
-
.tint(progressViewTint
|
|
141
|
+
.tint(progressViewTint.map { Color(hex: $0) })
|
|
137
142
|
.padding(.top, 5)
|
|
138
143
|
}
|
|
139
144
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// View+applyIfPresent.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Artur Bilski on 05/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import SwiftUI
|
|
9
|
+
|
|
10
|
+
extension View {
|
|
11
|
+
@ViewBuilder
|
|
12
|
+
func applyIfPresent<T>(_ value: T?, transform: (Self, T) -> some View) -> some View {
|
|
13
|
+
if let value {
|
|
14
|
+
transform(self, value)
|
|
15
|
+
} else {
|
|
16
|
+
self
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//
|
|
2
|
+
// View+applyWidgetURL.swift
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Created by Artur Bilski on 05/08/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import SwiftUI
|
|
9
|
+
|
|
10
|
+
extension View {
|
|
11
|
+
@ViewBuilder
|
|
12
|
+
func applyWidgetURL(from urlString: String?) -> some View {
|
|
13
|
+
applyIfPresent(urlString) { view, string in view.widgetURL(URL(string: string))}
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -12,12 +12,13 @@ export type LiveActivityState = {
|
|
|
12
12
|
dynamicIslandImageName?: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export type
|
|
15
|
+
export type LiveActivityConfig = {
|
|
16
16
|
backgroundColor?: string;
|
|
17
17
|
titleColor?: string;
|
|
18
18
|
subtitleColor?: string;
|
|
19
19
|
progressViewTint?: string;
|
|
20
20
|
progressViewLabelColor?: string;
|
|
21
|
+
deepLinkUrl?: string;
|
|
21
22
|
timerType?: DynamicIslandTimerType;
|
|
22
23
|
};
|
|
23
24
|
|
|
@@ -32,15 +33,15 @@ export type LiveActivityModuleEvents = {
|
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* @param {LiveActivityState} state The state for the live activity.
|
|
35
|
-
* @param {
|
|
36
|
+
* @param {LiveActivityConfig} config Live activity config object.
|
|
36
37
|
* @returns {string} The identifier of the started activity.
|
|
37
38
|
* @throws {Error} When function is called on a platform different from iOS.
|
|
38
39
|
*/
|
|
39
|
-
export function startActivity(state: LiveActivityState,
|
|
40
|
+
export function startActivity(state: LiveActivityState, config?: LiveActivityConfig): string {
|
|
40
41
|
if (Platform.OS !== "ios") {
|
|
41
42
|
throw new Error("startActivity is only available on iOS");
|
|
42
43
|
}
|
|
43
|
-
return ExpoLiveActivityModule.startActivity(state,
|
|
44
|
+
return ExpoLiveActivityModule.startActivity(state, config);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/**
|