| 1 | import { requireOptionalNativeModule } from "expo"; |
| 2 | import * as Linking from "expo-linking"; |
| 3 | import type { SubscriptionUsageSnapshot } from "./subscriptionUsageSnapshot"; |
| 4 | |
| 5 | let tapUrl: string | undefined; |
| 6 | let listening = false; |
| 7 | |
| 8 | export async function publishSubscriptionUsage(snapshot: SubscriptionUsageSnapshot) { |
| 9 | if (!requireOptionalNativeModule("ExpoWidgets")) return; |
| 10 | const [{ default: widget }, { addUserInteractionListener }] = await Promise.all([ |
| 11 | import("./SubscriptionUsage"), |
| 12 | import("expo-widgets"), |
| 13 | ]); |
| 14 | tapUrl = snapshot.url; |
| 15 | if (!listening) { |
| 16 | // expo-widgets has no Android counterpart to widgetURL: the card is a |
| 17 | // button whose tap is delivered to this process, so opening the app needs |
| 18 | // a live JS runtime. |
| 19 | listening = true; |
| 20 | addUserInteractionListener((event) => { |
| 21 | if (event.source === "SubscriptionUsage" && tapUrl) void Linking.openURL(tapUrl); |
| 22 | }); |
| 23 | } |
| 24 | widget.updateSnapshot(snapshot); |
| 25 | // Android has no timeline; an alarm re-renders the stored snapshot at each deadline. |
| 26 | requireOptionalNativeModule<{ schedule: (name: string, deadlines: number[]) => void }>( |
| 27 | "T3WidgetExpiry", |
| 28 | )?.schedule( |
| 29 | "SubscriptionUsage", |
| 30 | snapshot.providers.map((provider) => provider.expiresAt).filter((at) => at > 0), |
| 31 | ); |
| 32 | } |