Files
beenvoice-app/widgets/TimeClockActivity.tsx
T

115 lines
3.5 KiB
TypeScript

import { HStack, Image, Text, VStack } from "@expo/ui/swift-ui";
import {
frame,
font,
foregroundStyle,
layoutPriority,
lineLimit,
minimumScaleFactor,
monospacedDigit,
padding,
widgetAccentedRenderingMode,
} from "@expo/ui/swift-ui/modifiers";
import { createLiveActivity, type LiveActivityEnvironment } from "expo-widgets";
import type { TimeClockActivityProps } from "@/lib/time-clock-live-activity.types";
function TimeClockActivity(props: TimeClockActivityProps, _environment: LiveActivityEnvironment) {
"widget";
const island = "#FFFFFF";
const businessLabel = props.businessName.trim();
const clientLabel = props.clientName.trim();
const title = clientLabel || businessLabel || "Clock In";
const timerMods = [
font({ weight: "bold", size: 17 }),
foregroundStyle({ type: "hierarchical", style: "primary" }),
lineLimit(1),
minimumScaleFactor(0.75),
layoutPriority(2),
frame({ width: 100, alignment: "center" }),
];
const compactTimerMods = [
font({ design: "monospaced", weight: "semibold", size: 11 }),
monospacedDigit(),
foregroundStyle(island),
lineLimit(1),
minimumScaleFactor(0.75),
frame({ minWidth: 38, alignment: "center" }),
layoutPriority(2),
];
const clientMods = [
font({ weight: "bold", size: 17 }),
foregroundStyle({ type: "hierarchical", style: "primary" }),
lineLimit(1),
minimumScaleFactor(0.75),
];
// Avoid greedy layout primitives here: the live timerInterval Text can
// collapse when paired with Spacer/maxWidth. Fixed centered boxes keep the
// content stable without forcing left/right edge alignment.
const titleRowMods = [
layoutPriority(1),
frame({ width: 140, alignment: "center" }),
];
const sideZoneMods = [
frame({ width: 100, alignment: "center" }),
];
const bannerRowMods = [
padding({ horizontal: 10, vertical: 10 }),
frame({ maxWidth: Infinity, alignment: "center" }),
];
const bannerTimer = <Text modifiers={timerMods}>{props.elapsedShort}</Text>;
const compactTimer = <Text modifiers={compactTimerMods}>{props.elapsedShort}</Text>;
const logoLarge = (
<Image
assetName="SplashScreenLogo"
systemName="dollarsign.circle.fill"
size={22}
modifiers={[
foregroundStyle({ type: "hierarchical", style: "primary" }),
frame({ width: 22, height: 22 }),
widgetAccentedRenderingMode("fullColor"),
]}
/>
);
const logoSmall = (
<Image
systemName="dollarsign.circle.fill"
color={island}
size={14}
modifiers={[frame({ width: 14, height: 14 }), widgetAccentedRenderingMode("fullColor")]}
/>
);
return {
banner: (
<HStack alignment="center" spacing={8} modifiers={bannerRowMods}>
<VStack alignment="center" modifiers={sideZoneMods}>
{logoLarge}
</VStack>
<VStack alignment="center" spacing={1} modifiers={titleRowMods}>
<Text modifiers={clientMods}>{title}</Text>
</VStack>
{bannerTimer}
</HStack>
),
bannerSmall: (
<HStack alignment="center" spacing={8} modifiers={bannerRowMods}>
<VStack alignment="center" modifiers={sideZoneMods}>
{logoLarge}
</VStack>
<VStack alignment="center" spacing={1} modifiers={titleRowMods}>
<Text modifiers={clientMods}>{title}</Text>
</VStack>
{bannerTimer}
</HStack>
),
compactLeading: logoSmall,
compactTrailing: compactTimer,
minimal: logoSmall,
};
}
export default createLiveActivity("TimeClockActivity", TimeClockActivity);