Polish Live Activity branding and add EAS build config.
Use brand mark and wordmark images in the time clock Live Activity, migrate file copies to the modern expo-file-system File API, and add eas.json for TestFlight production builds. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { Platform } from "react-native";
|
||||
|
||||
import { formatElapsedHoursMinutes, formatElapsedSeconds } from "@/lib/time-clock";
|
||||
import type { TimeClockActivityProps } from "@/lib/time-clock-live-activity.types";
|
||||
import { ensureWidgetBrandAssets, getWidgetBrandAssetUris } from "@/lib/widget-brand-assets";
|
||||
|
||||
type RunningEntry = {
|
||||
description: string;
|
||||
@@ -54,6 +55,7 @@ export function buildTimeClockActivityProps(
|
||||
elapsedSeconds: number,
|
||||
): TimeClockActivityProps {
|
||||
const invoice = running.invoice;
|
||||
const brand = getWidgetBrandAssetUris();
|
||||
return {
|
||||
elapsed: formatElapsedSeconds(elapsedSeconds),
|
||||
elapsedShort: formatElapsedHoursMinutes(elapsedSeconds),
|
||||
@@ -66,6 +68,8 @@ export function buildTimeClockActivityProps(
|
||||
invoiceLabel: invoice
|
||||
? `${invoice.invoicePrefix ?? "#"}${invoice.invoiceNumber}`
|
||||
: "",
|
||||
markImageUri: brand?.markUri,
|
||||
logoImageUri: brand?.logoUri,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,6 +86,7 @@ export async function syncTimeClockLiveActivity(
|
||||
}
|
||||
|
||||
try {
|
||||
await ensureWidgetBrandAssets();
|
||||
const props = buildTimeClockActivityProps(running, elapsedSeconds);
|
||||
const instances = factory.getInstances();
|
||||
|
||||
|
||||
@@ -8,4 +8,8 @@ export type TimeClockActivityProps = {
|
||||
description: string;
|
||||
clientName: string;
|
||||
invoiceLabel: string;
|
||||
/** file:// URI to square dollar mark in the app-group widgets folder */
|
||||
markImageUri?: string;
|
||||
/** file:// URI to wordmark PNG in the app-group widgets folder */
|
||||
logoImageUri?: string;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Asset } from "expo-asset";
|
||||
import { File } from "expo-file-system";
|
||||
import { widgetsDirectory } from "expo-widgets";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
const MARK_FILE = "beenvoice-live-mark.png";
|
||||
const LOGO_FILE = "beenvoice-live-logo.png";
|
||||
|
||||
let cachedUris: { markUri: string; logoUri: string } | null = null;
|
||||
let copyPromise: Promise<{ markUri: string; logoUri: string } | null> | null = null;
|
||||
|
||||
async function copyBrandFile(fromUri: string, toUri: string) {
|
||||
await new File(fromUri).copy(new File(toUri), { overwrite: true });
|
||||
}
|
||||
|
||||
/** Copy brand PNGs into the app-group folder so the widget extension can read them. */
|
||||
export async function ensureWidgetBrandAssets(): Promise<{
|
||||
markUri: string;
|
||||
logoUri: string;
|
||||
} | null> {
|
||||
if (cachedUris) return cachedUris;
|
||||
if (copyPromise) return copyPromise;
|
||||
|
||||
copyPromise = (async () => {
|
||||
if (Platform.OS !== "ios" || !widgetsDirectory) return null;
|
||||
|
||||
const base = widgetsDirectory.endsWith("/") ? widgetsDirectory : `${widgetsDirectory}/`;
|
||||
const markUri = `${base}${MARK_FILE}`;
|
||||
const logoUri = `${base}${LOGO_FILE}`;
|
||||
|
||||
const markAsset = Asset.fromModule(require("@/assets/images/icon.png"));
|
||||
const logoAsset = Asset.fromModule(require("@/assets/images/beenvoice-logo-dark.png"));
|
||||
await Promise.all([markAsset.downloadAsync(), logoAsset.downloadAsync()]);
|
||||
|
||||
if (!markAsset.localUri || !logoAsset.localUri) return null;
|
||||
|
||||
await Promise.all([
|
||||
copyBrandFile(markAsset.localUri, markUri),
|
||||
copyBrandFile(logoAsset.localUri, logoUri),
|
||||
]);
|
||||
|
||||
cachedUris = { markUri, logoUri };
|
||||
return cachedUris;
|
||||
})();
|
||||
|
||||
try {
|
||||
return await copyPromise;
|
||||
} finally {
|
||||
copyPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getWidgetBrandAssetUris() {
|
||||
return cachedUris;
|
||||
}
|
||||
Reference in New Issue
Block a user