@use-voltra/android 2.3.2 → 2.4.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.
Files changed (74) hide show
  1. package/build/commonjs/index.js +25 -0
  2. package/build/commonjs/index.js.map +1 -1
  3. package/build/commonjs/jsx/primitives.js +36 -0
  4. package/build/commonjs/jsx/primitives.js.map +1 -1
  5. package/build/commonjs/modifiers/createAndroidModifier.js +20 -0
  6. package/build/commonjs/modifiers/createAndroidModifier.js.map +1 -0
  7. package/build/commonjs/modifiers/index.js +188 -0
  8. package/build/commonjs/modifiers/index.js.map +1 -0
  9. package/build/commonjs/ongoing-notification/components.js +7 -1
  10. package/build/commonjs/ongoing-notification/components.js.map +1 -1
  11. package/build/commonjs/ongoing-notification/renderer.js +354 -18
  12. package/build/commonjs/ongoing-notification/renderer.js.map +1 -1
  13. package/build/commonjs/ongoing-notification/types.js +56 -0
  14. package/build/commonjs/ongoing-notification/types.js.map +1 -1
  15. package/build/commonjs/server.js.map +1 -1
  16. package/build/module/index.js +3 -1
  17. package/build/module/index.js.map +1 -1
  18. package/build/module/jsx/primitives.js +1 -0
  19. package/build/module/jsx/primitives.js.map +1 -1
  20. package/build/module/modifiers/createAndroidModifier.js +15 -0
  21. package/build/module/modifiers/createAndroidModifier.js.map +1 -0
  22. package/build/module/modifiers/index.js +169 -0
  23. package/build/module/modifiers/index.js.map +1 -0
  24. package/build/module/ongoing-notification/components.js +6 -0
  25. package/build/module/ongoing-notification/components.js.map +1 -1
  26. package/build/module/ongoing-notification/renderer.js +354 -18
  27. package/build/module/ongoing-notification/renderer.js.map +1 -1
  28. package/build/module/ongoing-notification/types.js +55 -1
  29. package/build/module/ongoing-notification/types.js.map +1 -1
  30. package/build/module/server.js.map +1 -1
  31. package/build/typescript/commonjs/index.d.ts +4 -3
  32. package/build/typescript/commonjs/index.d.ts.map +1 -1
  33. package/build/typescript/commonjs/jsx/baseProps.d.ts +8 -0
  34. package/build/typescript/commonjs/jsx/baseProps.d.ts.map +1 -1
  35. package/build/typescript/commonjs/jsx/primitives.d.ts +1 -0
  36. package/build/typescript/commonjs/jsx/primitives.d.ts.map +1 -1
  37. package/build/typescript/commonjs/modifiers/createAndroidModifier.d.ts +13 -0
  38. package/build/typescript/commonjs/modifiers/createAndroidModifier.d.ts.map +1 -0
  39. package/build/typescript/commonjs/modifiers/index.d.ts +171 -0
  40. package/build/typescript/commonjs/modifiers/index.d.ts.map +1 -0
  41. package/build/typescript/commonjs/ongoing-notification/components.d.ts +8 -2
  42. package/build/typescript/commonjs/ongoing-notification/components.d.ts.map +1 -1
  43. package/build/typescript/commonjs/ongoing-notification/renderer.d.ts.map +1 -1
  44. package/build/typescript/commonjs/ongoing-notification/types.d.ts +281 -3
  45. package/build/typescript/commonjs/ongoing-notification/types.d.ts.map +1 -1
  46. package/build/typescript/commonjs/server.d.ts +1 -1
  47. package/build/typescript/commonjs/server.d.ts.map +1 -1
  48. package/build/typescript/module/index.d.ts +4 -3
  49. package/build/typescript/module/index.d.ts.map +1 -1
  50. package/build/typescript/module/jsx/baseProps.d.ts +8 -0
  51. package/build/typescript/module/jsx/baseProps.d.ts.map +1 -1
  52. package/build/typescript/module/jsx/primitives.d.ts +1 -0
  53. package/build/typescript/module/jsx/primitives.d.ts.map +1 -1
  54. package/build/typescript/module/modifiers/createAndroidModifier.d.ts +13 -0
  55. package/build/typescript/module/modifiers/createAndroidModifier.d.ts.map +1 -0
  56. package/build/typescript/module/modifiers/index.d.ts +171 -0
  57. package/build/typescript/module/modifiers/index.d.ts.map +1 -0
  58. package/build/typescript/module/ongoing-notification/components.d.ts +8 -2
  59. package/build/typescript/module/ongoing-notification/components.d.ts.map +1 -1
  60. package/build/typescript/module/ongoing-notification/renderer.d.ts.map +1 -1
  61. package/build/typescript/module/ongoing-notification/types.d.ts +281 -3
  62. package/build/typescript/module/ongoing-notification/types.d.ts.map +1 -1
  63. package/build/typescript/module/server.d.ts +1 -1
  64. package/build/typescript/module/server.d.ts.map +1 -1
  65. package/package.json +2 -2
  66. package/src/index.ts +36 -2
  67. package/src/jsx/baseProps.tsx +8 -0
  68. package/src/jsx/primitives.ts +1 -0
  69. package/src/modifiers/createAndroidModifier.ts +21 -0
  70. package/src/modifiers/index.ts +166 -0
  71. package/src/ongoing-notification/components.tsx +22 -1
  72. package/src/ongoing-notification/renderer.ts +451 -18
  73. package/src/ongoing-notification/types.ts +298 -4
  74. package/src/server.ts +15 -0
@@ -4,12 +4,84 @@ import type { ImageSource } from '../jsx/Image.js'
4
4
 
5
5
  export type AndroidOngoingNotificationFallbackBehavior = 'standard' | 'error'
6
6
 
7
+ /** Lock-screen and heads-up visibility, mapped onto `Notification.VISIBILITY_*` on Android. */
8
+ export const ANDROID_ONGOING_NOTIFICATION_VISIBILITIES = ['public', 'private', 'secret'] as const
9
+ export type AndroidOngoingNotificationVisibility = (typeof ANDROID_ONGOING_NOTIFICATION_VISIBILITIES)[number]
10
+
11
+ /**
12
+ * Notification categories Voltra exposes.
13
+ *
14
+ * Categories that carry do-not-disturb or ranking meaning for other notification kinds (`call`,
15
+ * `alarm`, `message`, and the rest) are deliberately absent: Voltra does not post those kinds, and
16
+ * picking one would change how an ongoing notification is treated beside unrelated notifications.
17
+ */
18
+ export const ANDROID_ONGOING_NOTIFICATION_CATEGORIES = [
19
+ 'progress',
20
+ 'navigation',
21
+ 'transport',
22
+ 'service',
23
+ 'status',
24
+ 'workout',
25
+ 'stopwatch',
26
+ 'location_sharing',
27
+ ] as const
28
+ export type AndroidOngoingNotificationCategory = (typeof ANDROID_ONGOING_NOTIFICATION_CATEGORIES)[number]
29
+
30
+ /**
31
+ * How the system should treat an ongoing notification for its whole lifetime.
32
+ *
33
+ * These belong in the options rather than the payload because they are a decision the app makes
34
+ * once and keeps: an update that does not mention them must not change them, and a server that only
35
+ * renders what the notification says has no business deciding them. Set them where you set
36
+ * `channelId`.
37
+ */
38
+ export type AndroidOngoingNotificationPresentationOptions = {
39
+ /** Lock-screen visibility. Unset keeps the system default, which is `'private'`. */
40
+ visibility?: AndroidOngoingNotificationVisibility
41
+ /** Accent color for the notification, as any static color string: `#1E88E5`, `rgb(30, 136, 229)`, or a name. */
42
+ color?: string
43
+ /** Overrides the category Voltra derives from the payload kind. */
44
+ category?: AndroidOngoingNotificationCategory
45
+ /**
46
+ * Remove the notification after this many milliseconds without an update. Applied on every post,
47
+ * so each update restarts the timer. Needs Android 8.0 or newer; the value is kept on older
48
+ * releases and applied once the device updates.
49
+ */
50
+ timeoutMs?: number
51
+ /** Keep the notification on this device instead of mirroring it to Wear or Android Auto. */
52
+ localOnly?: boolean
53
+ /** Group key, for the system bundle that collects this notification with siblings. */
54
+ group?: string
55
+ /** Orders this notification inside its group. */
56
+ sortKey?: string
57
+ /** Let the system add its own contextual actions, such as a directions chip. Defaults to the platform default, `true`. */
58
+ allowSystemGeneratedContextualActions?: boolean
59
+ }
60
+
61
+ /** The lock-screen copy of a notification whose private content should stay hidden there. */
62
+ export type AndroidOngoingNotificationPublicVersion = {
63
+ title: string
64
+ text?: string
65
+ }
66
+
67
+ /**
68
+ * Display props shared by both payload kinds.
69
+ *
70
+ * These travel in the payload rather than the options because they say what the notification means
71
+ * right now: like `title` and `text`, an update replaces them wholesale, so omitting `publicVersion`
72
+ * posts without one.
73
+ */
74
+ export type AndroidOngoingNotificationChronometer = boolean | 'countUp' | 'countDown'
75
+
7
76
  export type AndroidOngoingNotificationCommonDisplayProps = {
8
77
  title?: string
9
78
  subText?: string
10
79
  shortCriticalText?: string
11
80
  when?: Date | number
12
- chronometer?: boolean
81
+ chronometer?: AndroidOngoingNotificationChronometer
82
+ /** Show the timestamp. Defaults to true when `when` or `chronometer` is set, false otherwise. */
83
+ showWhen?: boolean
84
+ publicVersion?: AndroidOngoingNotificationPublicVersion
13
85
  }
14
86
 
15
87
  export type AndroidOngoingNotificationProgressSegment = {
@@ -55,6 +127,68 @@ export type AndroidOngoingNotificationBigTextProps = AndroidOngoingNotificationC
55
127
  children?: ReactNode
56
128
  }
57
129
 
130
+ export type AndroidOngoingNotificationBigPictureProps = AndroidOngoingNotificationCommonDisplayProps & {
131
+ picture: ImageSource
132
+ text?: string
133
+ summaryText?: string
134
+ pictureContentDescription?: string
135
+ showPictureWhenCollapsed?: boolean
136
+ largeIcon?: ImageSource
137
+ bigLargeIcon?: ImageSource
138
+ hideLargeIconWhenExpanded?: boolean
139
+ children?: ReactNode
140
+ }
141
+
142
+ export type AndroidOngoingNotificationInboxProps = AndroidOngoingNotificationCommonDisplayProps & {
143
+ lines: string[]
144
+ text?: string
145
+ summaryText?: string
146
+ largeIcon?: ImageSource
147
+ children?: ReactNode
148
+ }
149
+
150
+ export type AndroidOngoingNotificationMetricSemanticStyle = 'unspecified' | 'info' | 'safe' | 'caution' | 'danger'
151
+
152
+ export type AndroidOngoingNotificationMetricTimeFormat = 'adaptive' | 'chronometer'
153
+
154
+ /**
155
+ * A metric reading. Plain numbers and strings are shorthands: an integer becomes
156
+ * `int`, any other number becomes `float`, and a string becomes `text`.
157
+ */
158
+ export type AndroidOngoingNotificationMetricValue =
159
+ | { type: 'int'; value: number; unit?: string }
160
+ | {
161
+ type: 'float'
162
+ value: number
163
+ unit?: string
164
+ min?: number
165
+ max?: number
166
+ fractionDigits?: number
167
+ }
168
+ | { type: 'text'; value: string; unit?: string }
169
+ | { type: 'time'; value: string }
170
+ | { type: 'timer'; endsAt: number | Date; format?: AndroidOngoingNotificationMetricTimeFormat }
171
+ | { type: 'stopwatch'; startedAt: number | Date; format?: AndroidOngoingNotificationMetricTimeFormat }
172
+ | { type: 'pausedTimer'; remainingMillis: number }
173
+ | { type: 'pausedStopwatch'; elapsedMillis: number }
174
+ | number
175
+ | string
176
+
177
+ export type AndroidOngoingNotificationMetricDescriptor = {
178
+ label: string
179
+ value: AndroidOngoingNotificationMetricValue
180
+ /** Shorthand for the unit of a number value; moved into the value object when rendering. */
181
+ unit?: string
182
+ }
183
+
184
+ export type AndroidOngoingNotificationMetricProps = AndroidOngoingNotificationCommonDisplayProps & {
185
+ metrics: AndroidOngoingNotificationMetricDescriptor[]
186
+ criticalMetric?: number
187
+ semanticStyle?: AndroidOngoingNotificationMetricSemanticStyle
188
+ largeIcon?: ImageSource
189
+ children?: ReactNode
190
+ }
191
+
58
192
  export type AndroidOngoingNotificationProgressPayload = {
59
193
  v: 1
60
194
  kind: 'progress'
@@ -67,7 +201,10 @@ export type AndroidOngoingNotificationProgressPayload = {
67
201
  shortCriticalText?: string
68
202
  when?: number
69
203
  chronometer?: boolean
204
+ chronometerCountDown?: boolean
205
+ showWhen?: boolean
70
206
  largeIcon?: ImageSource
207
+ publicVersion?: AndroidOngoingNotificationPublicVersion
71
208
  progressTrackerIcon?: ImageSource
72
209
  progressStartIcon?: ImageSource
73
210
  progressEndIcon?: ImageSource
@@ -86,13 +223,99 @@ export type AndroidOngoingNotificationBigTextPayload = {
86
223
  shortCriticalText?: string
87
224
  when?: number
88
225
  chronometer?: boolean
226
+ chronometerCountDown?: boolean
227
+ showWhen?: boolean
228
+ largeIcon?: ImageSource
229
+ publicVersion?: AndroidOngoingNotificationPublicVersion
230
+ actions?: AndroidOngoingNotificationActionPayload[]
231
+ }
232
+
233
+ export type AndroidOngoingNotificationBigPicturePayload = {
234
+ v: 1
235
+ kind: 'bigPicture'
236
+ title?: string
237
+ subText?: string
238
+ text?: string
239
+ picture: ImageSource
240
+ summaryText?: string
241
+ pictureContentDescription?: string
242
+ showPictureWhenCollapsed?: boolean
243
+ largeIcon?: ImageSource
244
+ bigLargeIcon?: ImageSource
245
+ hideLargeIconWhenExpanded?: boolean
246
+ shortCriticalText?: string
247
+ when?: number
248
+ chronometer?: boolean
249
+ chronometerCountDown?: boolean
250
+ showWhen?: boolean
251
+ publicVersion?: AndroidOngoingNotificationPublicVersion
252
+ actions?: AndroidOngoingNotificationActionPayload[]
253
+ }
254
+
255
+ export type AndroidOngoingNotificationInboxPayload = {
256
+ v: 1
257
+ kind: 'inbox'
258
+ title?: string
259
+ subText?: string
260
+ text: string
261
+ lines: string[]
262
+ summaryText?: string
263
+ shortCriticalText?: string
264
+ when?: number
265
+ chronometer?: boolean
266
+ chronometerCountDown?: boolean
267
+ showWhen?: boolean
268
+ largeIcon?: ImageSource
269
+ publicVersion?: AndroidOngoingNotificationPublicVersion
270
+ actions?: AndroidOngoingNotificationActionPayload[]
271
+ }
272
+
273
+ export type AndroidOngoingNotificationMetricValuePayload =
274
+ | { type: 'int'; value: number; unit?: string }
275
+ | {
276
+ type: 'float'
277
+ value: number
278
+ unit?: string
279
+ min?: number
280
+ max?: number
281
+ fractionDigits?: number
282
+ }
283
+ | { type: 'text'; value: string; unit?: string }
284
+ | { type: 'time'; value: string }
285
+ | { type: 'timer'; endsAt: number; format?: AndroidOngoingNotificationMetricTimeFormat }
286
+ | { type: 'stopwatch'; startedAt: number; format?: AndroidOngoingNotificationMetricTimeFormat }
287
+ | { type: 'pausedTimer'; remainingMillis: number }
288
+ | { type: 'pausedStopwatch'; elapsedMillis: number }
289
+
290
+ export type AndroidOngoingNotificationMetricEntryPayload = {
291
+ label: string
292
+ value: AndroidOngoingNotificationMetricValuePayload
293
+ }
294
+
295
+ export type AndroidOngoingNotificationMetricPayload = {
296
+ v: 1
297
+ kind: 'metric'
298
+ title?: string
299
+ subText?: string
300
+ shortCriticalText?: string
301
+ when?: number
302
+ chronometer?: boolean
303
+ chronometerCountDown?: boolean
304
+ showWhen?: boolean
89
305
  largeIcon?: ImageSource
306
+ publicVersion?: AndroidOngoingNotificationPublicVersion
307
+ metrics: AndroidOngoingNotificationMetricEntryPayload[]
308
+ criticalMetric?: number
309
+ semanticStyle?: AndroidOngoingNotificationMetricSemanticStyle
90
310
  actions?: AndroidOngoingNotificationActionPayload[]
91
311
  }
92
312
 
93
313
  export type AndroidOngoingNotificationPayload =
94
314
  | AndroidOngoingNotificationProgressPayload
95
315
  | AndroidOngoingNotificationBigTextPayload
316
+ | AndroidOngoingNotificationBigPicturePayload
317
+ | AndroidOngoingNotificationInboxPayload
318
+ | AndroidOngoingNotificationMetricPayload
96
319
 
97
320
  export type AndroidOngoingNotificationContent = ReactNode
98
321
 
@@ -108,12 +331,47 @@ export type StartAndroidOngoingNotificationOptions = {
108
331
  deepLinkUrl?: string
109
332
  requestPromotedOngoing?: boolean
110
333
  fallbackBehavior?: AndroidOngoingNotificationFallbackBehavior
111
- }
334
+ } & AndroidOngoingNotificationPresentationOptions
335
+
336
+ /** An update can send `null` for a presentation option to clear the value stored at start. */
337
+ type Clearable<T> = { [K in keyof T]?: T[K] | null }
112
338
 
339
+ /**
340
+ * Options for one update.
341
+ *
342
+ * Presentation options are three-state: leave a key out to keep what the running notification
343
+ * already uses, send `null` to clear it, or send a value to replace and store it. Every other key
344
+ * keeps the existing merge behaviour, where an omitted key reuses the stored value.
345
+ */
113
346
  export type UpdateAndroidOngoingNotificationOptions = Omit<
114
347
  Partial<StartAndroidOngoingNotificationOptions>,
115
- 'notificationId'
116
- >
348
+ 'notificationId' | keyof AndroidOngoingNotificationPresentationOptions
349
+ > &
350
+ Clearable<AndroidOngoingNotificationPresentationOptions> & {
351
+ /**
352
+ * Let this update make a sound, vibrate or show lights the way a first post does, instead of
353
+ * updating silently. Applies to this post only and is never stored, so the next update is quiet
354
+ * again unless it asks.
355
+ */
356
+ alert?: boolean
357
+ }
358
+
359
+ /**
360
+ * Options for starting or updating with one call.
361
+ *
362
+ * The shape of start plus what only an update can use: a presentation option sent as `null` clears
363
+ * the stored value when the notification already exists, and `alert` lets that update branch alert.
364
+ * On the start branch neither changes anything, because nothing is stored yet and a first post
365
+ * always alerts.
366
+ */
367
+ export type UpsertAndroidOngoingNotificationOptions = Omit<
368
+ StartAndroidOngoingNotificationOptions,
369
+ keyof AndroidOngoingNotificationPresentationOptions
370
+ > &
371
+ Clearable<AndroidOngoingNotificationPresentationOptions> & {
372
+ /** Let the update branch make a sound the way a first post does. A start branch always alerts. */
373
+ alert?: boolean
374
+ }
117
375
 
118
376
  export type UseAndroidOngoingNotificationOptions = StartAndroidOngoingNotificationOptions & {
119
377
  autoStart?: boolean
@@ -135,12 +393,44 @@ export type AndroidOngoingNotificationStatus = {
135
393
  hasPromotableCharacteristics?: boolean
136
394
  }
137
395
 
396
+ export type AndroidOngoingNotificationPromotionIssue =
397
+ | 'unsupported_api_level'
398
+ | 'permission_not_declared'
399
+ | 'notifications_disabled'
400
+ | 'promotion_disabled_by_user'
401
+ | 'channel_importance_min'
402
+ | 'missing_title'
403
+ | 'not_promotable'
404
+
405
+ export type AndroidOngoingNotificationPromotionInfo = {
406
+ requested: boolean
407
+ eligible: boolean
408
+ reasons: AndroidOngoingNotificationPromotionIssue[]
409
+ hasPromotableCharacteristics?: boolean
410
+ }
411
+
412
+ export type CheckAndroidOngoingNotificationPromotionOptions = Pick<
413
+ StartAndroidOngoingNotificationOptions,
414
+ 'channelId' | 'smallIcon'
415
+ >
416
+
417
+ export type AndroidOngoingNotificationCheckPromotionResult = {
418
+ eligible: boolean
419
+ reasons: AndroidOngoingNotificationPromotionIssue[]
420
+ hasPromotableCharacteristics?: boolean
421
+ }
422
+
423
+ /** Set when a style the device cannot show yet was posted as a standard notification. */
424
+ export type AndroidOngoingNotificationStyleFallback = 'standard'
425
+
138
426
  export type AndroidOngoingNotificationStartResult =
139
427
  | {
140
428
  ok: true
141
429
  notificationId: string
142
430
  action: 'started'
143
431
  reason?: undefined
432
+ promotion?: AndroidOngoingNotificationPromotionInfo
433
+ styleFallback?: AndroidOngoingNotificationStyleFallback
144
434
  }
145
435
  | {
146
436
  ok: false
@@ -155,6 +445,8 @@ export type AndroidOngoingNotificationUpdateResult =
155
445
  notificationId: string
156
446
  action: 'updated'
157
447
  reason?: undefined
448
+ promotion?: AndroidOngoingNotificationPromotionInfo
449
+ styleFallback?: AndroidOngoingNotificationStyleFallback
158
450
  }
159
451
  | {
160
452
  ok: false
@@ -169,6 +461,8 @@ export type AndroidOngoingNotificationUpsertResult =
169
461
  notificationId: string
170
462
  action: 'started' | 'updated'
171
463
  reason?: undefined
464
+ promotion?: AndroidOngoingNotificationPromotionInfo
465
+ styleFallback?: AndroidOngoingNotificationStyleFallback
172
466
  }
173
467
  | {
174
468
  ok: false
package/src/server.ts CHANGED
@@ -6,14 +6,29 @@ export {
6
6
  export type {
7
7
  AndroidOngoingNotificationActionPayload,
8
8
  AndroidOngoingNotificationActionProps,
9
+ AndroidOngoingNotificationBigPicturePayload,
10
+ AndroidOngoingNotificationBigPictureProps,
9
11
  AndroidOngoingNotificationBigTextPayload,
10
12
  AndroidOngoingNotificationBigTextProps,
13
+ AndroidOngoingNotificationChronometer,
14
+ AndroidOngoingNotificationCommonDisplayProps,
11
15
  AndroidOngoingNotificationContent,
16
+ AndroidOngoingNotificationInboxPayload,
17
+ AndroidOngoingNotificationInboxProps,
18
+ AndroidOngoingNotificationMetricDescriptor,
19
+ AndroidOngoingNotificationMetricEntryPayload,
20
+ AndroidOngoingNotificationMetricPayload,
21
+ AndroidOngoingNotificationMetricProps,
22
+ AndroidOngoingNotificationMetricSemanticStyle,
23
+ AndroidOngoingNotificationMetricTimeFormat,
24
+ AndroidOngoingNotificationMetricValue,
25
+ AndroidOngoingNotificationMetricValuePayload,
12
26
  AndroidOngoingNotificationPayload,
13
27
  AndroidOngoingNotificationProgressPayload,
14
28
  AndroidOngoingNotificationProgressPoint,
15
29
  AndroidOngoingNotificationProgressProps,
16
30
  AndroidOngoingNotificationProgressSegment,
31
+ AndroidOngoingNotificationPublicVersion,
17
32
  } from './ongoing-notification/types.js'
18
33
  export { renderAndroidWidgetToString } from './widgets/renderer.js'
19
34
  export type { AndroidColorValue, AndroidDynamicColorRole, AndroidDynamicColorToken } from './dynamic-colors.js'