one
Version:
One is a React framework for web, iOS, and Android apps.
109 lines (98 loc) • 4.24 kB
text/typescript
import { NativeEventEmitter, NativeModules, Platform } from 'react-native'
import type { ReactNode } from 'react'
import { encodeActivityView, encodeWidgetView, type ActivityView } from './view'
import { LiveActivities as unavailableLiveActivities } from './unavailable'
export { WidgetUI, type WidgetStyle, type ActivityView } from './view'
export type WidgetData = { title: string; value: string; subtitle: string }
export type LiveActivityState = { status: string; value: string }
export type PushTokenEvent = { id: string; token: string }
interface WidgetsBridge {
writeWidget(title: string, value: string, subtitle: string): Promise<void>
writeView(layout: string): Promise<void>
start(title: string, status: string, value: string, push: boolean): Promise<string>
startView(title: string, layout: string, push: boolean): Promise<string>
update(id: string, status: string, value: string): Promise<void>
updateView(id: string, layout: string): Promise<void>
end(id: string): Promise<void>
pushToken(id: string): Promise<string | null>
addListener(event: string): void
removeListeners(count: number): void
}
function bridge(): WidgetsBridge {
const native = NativeModules.OneWidgetsBridge as WidgetsBridge | undefined
if (!native)
throw new Error('iOS widgets require native.app.ios.widgets and a new iOS build')
return native
}
const nativeWidgets = Object.freeze({
write(data: WidgetData): Promise<void> {
return bridge().writeWidget(data.title, data.value, data.subtitle)
},
writeView(view: ReactNode): Promise<void> {
return bridge().writeView(encodeWidgetView(view))
},
})
const nativeLiveActivities = Object.freeze({
start(title: string, state: LiveActivityState, push = false): Promise<string> {
return bridge().start(title, state.status, state.value, push)
},
startView(title: string, view: ActivityView, push = false): Promise<string> {
return bridge().startView(title, encodeActivityView(view), push)
},
update(id: string, state: LiveActivityState): Promise<void> {
return bridge().update(id, state.status, state.value)
},
updateView(id: string, view: ActivityView): Promise<void> {
return bridge().updateView(id, encodeActivityView(view))
},
end(id: string): Promise<void> {
return bridge().end(id)
},
pushToken(id: string): Promise<string | null> {
return bridge().pushToken(id)
},
onPushToken(listener: (event: PushTokenEvent) => void): () => void {
const subscription = new NativeEventEmitter(bridge()).addListener(
'oneLiveActivityPushToken',
listener
)
return () => subscription.remove()
},
})
function androidLimit(operation: string): Error {
return new Error(`${operation} requires an iOS native build`)
}
const androidWidgets = Object.freeze({
write(_data: WidgetData): Promise<void> {
return Promise.reject(androidLimit('Widgets.write'))
},
writeView(_view: ReactNode): Promise<void> {
return Promise.reject(androidLimit('Widgets.writeView'))
},
})
const androidLiveActivities = Object.freeze({
...unavailableLiveActivities,
start(_title: string, _state: LiveActivityState, _push = false): Promise<string> {
return Promise.reject(androidLimit('LiveActivities.start'))
},
startView(_title: string, _view: ActivityView, _push = false): Promise<string> {
return Promise.reject(androidLimit('LiveActivities.startView'))
},
update(_id: string, _state: LiveActivityState): Promise<void> {
return Promise.reject(androidLimit('LiveActivities.update'))
},
updateView(_id: string, _view: ActivityView): Promise<void> {
return Promise.reject(androidLimit('LiveActivities.updateView'))
},
end(_id: string): Promise<void> {
return Promise.reject(androidLimit('LiveActivities.end'))
},
onPushToken(_listener: (event: PushTokenEvent) => void): () => void {
throw androidLimit('LiveActivities.onPushToken')
},
})
// widgetkit and activitykit are iOS only; Android action methods report that limit.
export const Widgets: typeof nativeWidgets =
Platform.OS === 'android' ? androidWidgets : nativeWidgets
export const LiveActivities: typeof nativeLiveActivities =
Platform.OS === 'android' ? androidLiveActivities : nativeLiveActivities