All checks were successful
build-apk / build (push) Successful in 40m22s
For a zone labeled free_2h/3h/4h, "Check in (free · Xh)" starts a local, API-free countdown to the free limit — no ParkSmarter call. The bbp-notify module gains a showCheckin() that posts the ticking chronometer with "End" / "Pay" buttons, a BbpActionReceiver (declared in the module's new AndroidManifest.xml) that records the tap in SharedPreferences and, for Pay, relaunches the app; consumePendingAction() is drained on foreground by useCheckinSync() — End clears the check-in, Pay hands off to StartSession for the stored zone. A pre-expiry alert reuses the existing reminder lead-minutes. Starting a paid session supersedes an active check-in. Also: MeterDetail shows the free/pay-immediate label and (admins) labeling chips. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
2 KiB
TypeScript
64 lines
2 KiB
TypeScript
import { Platform } from 'react-native';
|
|
import { requireOptionalNativeModule } from 'expo-modules-core';
|
|
|
|
interface BbpNotifyNative {
|
|
/**
|
|
* Post/replace an ongoing notification with a native chronometer counting down
|
|
* to endTimeMillis. Returns a short diagnostic string (e.g. "posted enabled=true").
|
|
*/
|
|
showCountdown(title: string, body: string, endTimeMillis: number): Promise<string>;
|
|
/** Same ticking countdown, plus "End" / "Pay" action buttons. */
|
|
showCheckin(
|
|
title: string,
|
|
body: string,
|
|
endTimeMillis: number,
|
|
endLabel: string,
|
|
payLabel: string,
|
|
): Promise<string>;
|
|
/** Remove the countdown notification. */
|
|
clear(): Promise<void>;
|
|
/** Read + clear the action a notification button set: 'end' | 'pay' | ''. */
|
|
consumePendingAction(): Promise<string>;
|
|
}
|
|
|
|
export type PendingAction = 'end' | 'pay' | null;
|
|
|
|
// Android-only, and only present in a build that includes the native module
|
|
// (returns null in Expo Go / other platforms — callers degrade gracefully).
|
|
const native =
|
|
Platform.OS === 'android'
|
|
? (requireOptionalNativeModule('BbpNotify') as BbpNotifyNative | null)
|
|
: null;
|
|
|
|
/** True when the native ticking-countdown module is available. */
|
|
export const hasNativeCountdown = native != null;
|
|
|
|
export async function showCountdown(
|
|
title: string,
|
|
body: string,
|
|
endTimeMillis: number,
|
|
): Promise<string> {
|
|
if (!native) return 'no-native-module';
|
|
return native.showCountdown(title, body, endTimeMillis);
|
|
}
|
|
|
|
export async function showCheckin(
|
|
title: string,
|
|
body: string,
|
|
endTimeMillis: number,
|
|
endLabel: string,
|
|
payLabel: string,
|
|
): Promise<string> {
|
|
if (!native) return 'no-native-module';
|
|
return native.showCheckin(title, body, endTimeMillis, endLabel, payLabel);
|
|
}
|
|
|
|
export async function clearCountdown(): Promise<void> {
|
|
await native?.clear();
|
|
}
|
|
|
|
/** Read + clear a notification-button action taken while the app was away. */
|
|
export async function consumePendingAction(): Promise<PendingAction> {
|
|
const a = await native?.consumePendingAction();
|
|
return a === 'end' || a === 'pay' ? a : null;
|
|
}
|