Package-level declarations

Types

Link copied to clipboard
data class AnalyticsEvent(val type: String, val params: Map<String, String> = emptyMap())

A single analytics event. Param keys/values self-clamp to Firebase limits (≤ 40-char name/key, ≤ 100-char value, ≤ 25 params) so impls never reject an event.

Link copied to clipboard
interface AnalyticsHelper

Analytics sink. gms: FirebaseAnalytics (app-side); noGms + iOS + desktop: LoggingAnalyticsHelper.

Link copied to clipboard

Android FilePicker. Calf's rememberFilePickerLauncher/rememberFileSaverLauncher are @Composable (they wrap rememberLauncherForActivityResult), so — mirroring AndroidPermissionsProvider.requestBridge — the host activity's Compose layer registers pickBridge/saveBridge to the real launchers; with no bridge registered this degrades to reporting no file rather than crashing. File bytes are read via Calf's KmpFile I/O, which is plain suspend code, not Compose-bound.

Link copied to clipboard

Android ForwardGeocoder via Compass's mobile geocoder, itself android.location.Geocoder underneath — the same OS geocoder AndroidLocationNameResolver wraps for the reverse direction.

Link copied to clipboard

Android LocationNameResolver backed by the platform Geocoder (reverse geocoding).

Link copied to clipboard

Android LocationTracker backed by the fused location provider.

Link copied to clipboard
class AndroidNotificationScheduler(context: Context, channelId: String = DEFAULT_CHANNEL_ID, channelName: String = "General", importance: Int = NotificationManager.IMPORTANCE_DEFAULT) : NotificationScheduler
Link copied to clipboard

Android PermissionsProvider. isGranted is a plain ContextCompat.checkSelfPermission sweep. request needs an Activity to show the system dialog, so the foreground activity registers a requestBridge (ActivityResult-based); with no bridge registered (headless/no UI host) it degrades to reporting the current grant state instead of crashing.

Link copied to clipboard

Android PlaceAutocomplete via Compass's mobile autocomplete — under the hood it matches partial input against the same android.location.Geocoder AndroidForwardGeocoder uses, not a separate typeahead service, so it needs no API key. Same context-free construction as AndroidForwardGeocoder.

Link copied to clipboard

Runtime permissions the app requests.

Link copied to clipboard

In-app review prompt. Android: Play review (gms) / store intent (noGms). iOS: SKStoreReviewController.

Link copied to clipboard

Creates an Activity-scoped AppReviewManager.

Link copied to clipboard

In-app update. Android: Play-Core AppUpdateManager (gms) / no-op (noGms). iOS: iTunes Lookup API version compare. Typically Activity/UIViewController-scoped on Android via AppUpdateManagerFactory — the gms-specific impl is app-side, not part of this module (see AppUpdateManagerFactory doc).

Link copied to clipboard

Creates an Activity-scoped AppUpdateManager.

Link copied to clipboard
interface DocumentScanner

Document scanning → captured page images as bytes. Android: ML Kit doc scanner; iOS: VisionKit.

Link copied to clipboard
interface FilePicker

File selection for import/export flows (e.g. picking a receipt, saving an export). Android/iOS: Calf's file-picker/file-saver, bridged from the host's Compose layer — Calf's launchers are @Composable (they wrap rememberLauncherForActivityResult/UIDocumentPickerViewController), so like PermissionsProvider.request's ActivityResult dialog, the actual pick/save UI can't be driven from this headless module and is bridged in by whoever hosts the Compose UI.

Link copied to clipboard
interface ForwardGeocoder

Resolves free-text address input to coordinates (forward geocoding — the counterpart to LocationNameResolver's reverse direction). Android/iOS: Compass, itself a thin wrapper over the same OS geocoders LocationNameResolver already wraps (android.location.Geocoder / CLGeocoder).

Link copied to clipboard
data class GeoCoordinates(val latitude: Double, val longitude: Double)

A plain lat/lng pair — the forward-geocoding counterpart of PlaceName's coordinate string.

Link copied to clipboard
data class GeoPlace(val label: String, val coordinates: GeoCoordinates)

A place suggestion: a human-readable label plus its resolvable coordinates.

Link copied to clipboard
data class GeoPoint(val latitude: Double, val longitude: Double, val accuracyMeters: Float = 0.0f, val timestampMillis: Long = 0, val speedMetersPerSecond: Float = -1f, val courseDegrees: Double = -1.0, val altitudeMeters: Double = 0.0)

A platform-neutral geographic sample.

Link copied to clipboard

Process-lifetime in-memory token store (default / test double).

Link copied to clipboard
class InMemoryReviewStateStore(initial: ReviewState = ReviewState()) : ReviewStateStore

Process-lifetime in-memory store (default / test double; resets on cold start).

Link copied to clipboard

iOS in-app review (parity with the Android Play-review path). Uses the iOS 14+ window-scene variant of SKStoreReviewController; if no foreground-active window scene is found it simply does nothing (matches the "host may decline" semantics of the Android impl). Never crashes.

Link copied to clipboard
class IosAppUpdateManager(bundleId: String? = NSBundle.mainBundle.bundleIdentifier, currentVersion: String = (NSBundle.mainBundle.objectForInfoDictionaryKey("CFBundleShortVersionString") as? String) ?: "0", httpClient: HttpClient = HttpClient(Darwin)) : AppUpdateManager

iOS in-app update via the public iTunes Lookup API (no backend, parity with the Android Play-Core path). Compares the App Store version to the running CFBundleShortVersionString. startUpdate opens the App Store page. Any network/parse failure → UpdateAvailability.NotAvailable, never a crash.

Link copied to clipboard

iOS document scanning.

Link copied to clipboard

iOS FilePicker. Calf's file-picker/file-saver launchers are @Composable — like IosDocumentScanner's VisionKit flow, they must be presented from live Compose UI, which this headless module has no hook into. Mirroring AndroidFilePicker, the host's Compose layer wires pickBridge/saveBridge to the real launchers; with no bridge registered this degrades to reporting no file, the same truthful-no-op fallback IosDocumentScanner uses.

Link copied to clipboard

iOS ForwardGeocoder via Compass's mobile geocoder, itself CLGeocoder underneath — the same OS geocoder IosLocationNameResolver wraps for the reverse direction. Needs no context, same as IosLocationNameResolver.

Link copied to clipboard

iOS LocationNameResolver via CoreLocation's CLGeocoder (the CLGeocoder counterpart to Android's Geocoder). reverseGeocodeLocation is asynchronous and callback-based; it is bridged to a suspend point with suspendCancellableCoroutine.

Link copied to clipboard

iOS location via CoreLocation, counterpart to Android's FusedLocationProvider.

Link copied to clipboard

iOS local notifications via UNUserNotificationCenter, the counterpart to Android's NotificationManager + channels. ensurePermission bridges requestAuthorization's completion handler into a suspend call; notify posts an immediate (trigger=null) request keyed by the int id.

Link copied to clipboard

iOS runtime permissions, queries/requests the per-capability authorization APIs (camera = AVCaptureDevice, location = CLLocationManager, notifications = UNUserNotificationCenter). Storage has no broad user-facing prompt on iOS, so it is always granted. Location grants surface asynchronously through the CLLocationManager delegate, so request for it is fire-and-forget and the result is read back later via isGranted.

Link copied to clipboard

iOS PlaceAutocomplete via Compass's mobile autocomplete — under the hood it matches partial input against the same CLGeocoder IosForwardGeocoder uses, not a separate typeahead service, so it needs no API key. Same context-free construction as IosForwardGeocoder.

Link copied to clipboard
class LocalPushMessaging(store: PushTokenStore = InMemoryPushTokenStore()) : PushMessaging

Offline PushMessaging backed by a PushTokenStore — the commonMain default (and the noGms/ iOS-without-key fallback) for apps with no push backend of their own to register against.

Link copied to clipboard

Resolves a coordinate to a short, human-readable place name (reverse geocoding).

Link copied to clipboard
interface LocationTracker

Continuous + one-shot location access. Android: FusedLocation; iOS: CoreLocation.

Link copied to clipboard

Analytics sink that logs (self-clamped) events via Napier. This is the noGms + iOS + desktop analytics impl (no real backend); a gms-style app binds a Firebase-backed helper of its own instead.

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard

Local notifications. Android: NotificationManager + channels; iOS: UNUserNotificationCenter.

Link copied to clipboard
data class PermissionFlowState(val steps: List<PermissionStep>, val currentIndex: Int)

Snapshot of a permission flow.

Link copied to clipboard

Sequential permission-request state machine over a PermissionsProvider. Walks a fixed sequence one permission at a time: each step is skipped if already granted, otherwise requestCurrent asks for it, records the PermissionResult, and advances. Pure orchestration over the platform provider, no Android / iOS types, so it is fully covered by JVM unit tests with a fake provider. The UI observes state and calls requestCurrent from a button; runAll auto-walks the whole sequence.

Link copied to clipboard
sealed interface PermissionResult
Link copied to clipboard

Runtime permission requests. Android: ActivityResult; iOS: the per-capability authorization APIs.

Link copied to clipboard
data class PermissionStep(val permission: AppPermission, val result: PermissionResult? = null)

One permission in a PermissionOrchestrator flow and its latest result (null = not yet decided).

Link copied to clipboard

Place-name autocomplete for an in-progress address search. Android/iOS: Compass's mobile autocomplete, which matches partial input against the same OS geocoder ForwardGeocoder uses — there is no separate typeahead network call or API key, so availability mirrors ForwardGeocoder.

Link copied to clipboard
data class PlaceName(val name: String?, val coordinates: String)

The outcome of a reverse-geocode lookup.

Link copied to clipboard
interface PushMessaging

Push token + topic surface. Android: FCM (gms) / no-op (noGms). iOS: APNs + Firebase.

Link copied to clipboard
interface PushTokenStore

Local persistence for the push token + subscribed topics. Platform impls push tokens here; topic subscribe/unsubscribe is local bookkeeping — remote registration against a backend is the app's job.

Link copied to clipboard

Pure engagement-gating logic for the in-app review prompt.

Link copied to clipboard
data class ReviewGateConfig(val minAccountAgeDays: Int = 3, val minInteractions: Int = 5, val cooldownDays: Int = 30)

Tunable thresholds for the review gate (sane defaults; overridable via app config).

Link copied to clipboard
data class ReviewState(val firstOpenMillis: Long = 0, val interactionCount: Int = 0, val lastPromptMillis: Long = 0)

Persisted review counters (app-persisted — DataStore/NSUserDefaults/etc. in production).

Link copied to clipboard

Persistence for the review counters. Default in-memory; the app can swap a durable-store impl.

Link copied to clipboard
class ReviewTracker(store: ReviewStateStore = InMemoryReviewStateStore(), config: ReviewGateConfig = ReviewGateConfig(), now: () -> Long = { Clock.System.now().toEpochMilliseconds() })

Drives the in-app review prompt from engagement signals. Records first-open + interaction counts, and prompts (via the platform AppReviewManager) only when ReviewEligibility is satisfied, then stamps the prompt time to enforce the cooldown.

Link copied to clipboard
sealed interface UpdateAvailability

Result of querying the store for a newer build.

Link copied to clipboard
data class UpdateConfig(val enabled: Boolean = false, val mode: UpdateMode = UpdateMode.FLEXIBLE, val minSupportedVersionCode: Long = 0, val staleDays: Int = 0, val priority: Int = 0)

Gate config for the in-app update flow (mirrors a remote splash/config API).

Link copied to clipboard

How an available update should be applied.