feat(surveys): add posthog-android-surveys-compose default UI module#541
Draft
leonhardprinz wants to merge 4 commits into
Draft
feat(surveys): add posthog-android-surveys-compose default UI module#541leonhardprinz wants to merge 4 commits into
leonhardprinz wants to merge 4 commits into
Conversation
Adds a new optional Gradle module `posthog-android-surveys-compose` that ports the iOS SwiftUI survey UI (PostHog/posthog-ios#320) to Jetpack Compose. Closes the long-standing gap in #102: the SDK's default `PostHogSurveysDelegate` only logs, so customers have had to ship their own UI. Driven by Fujifilm (20+ INSTAX apps) who are blocked rolling out NPS surveys on Android. Disclosure: vibe-coded by a TAM using PostHog Code with the iOS implementation as the port-from blueprint. MVP scope (this commit): - NPS / Number Rating question type only (0–10, 1–5, 1–7 scales) - Material 3 ModalBottomSheet container with `confirmValueChange` intercept so only the X button dismisses (matches iOS `interactiveDismissDisabled` semantics) - Theming sourced from PostHogDisplaySurveyAppearance — faithful port of the iOS hex/CSS-name color parser (140-entry color table) - onSurveyShown / onSurveyResponse / onSurveyClosed callbacks wired so the core SDK fires `survey shown` / `survey sent` / `survey dismissed` events correctly - ComposeView injected into the foreground Activity's android.R.id.content via an ActivityLifecycleCallbacks-backed ActivityProvider — works on any Activity type - @Preview composables (default + themed) - Sample app wired with `Trigger test survey` button capturing `show_test_survey` Out of MVP (planned follow-ups): open-text/choice/link questions, emoji rating, thank-you screen, multi-question branching coverage, dark-mode polish, Compose UI tests, accessibility audit. Architecture: - Separate Gradle module — non-Compose customers don't pay APK-size cost. Mirrors how AndroidX ships optional Compose modules. - Independent versioning starting at 1.0.0-alpha01 — lets the module iterate through alphas without dragging core SDK versions. - Compose BOM 2024.12.01 (same as the sample app). - No changes to `:posthog` or `:posthog-android` modules; no public API changes; module excluded from binary-compatibility-validator during alpha. Refs: #102 Generated-By: PostHog Code Task-Id: b89cbdd1-9f16-4fa4-b3d0-3f9b268b0c2b
Android Lint's AutoboxingStateCreation rule (warningsAsErrors enabled) flagged mutableStateOf(0) for the question index. Switching to mutableIntStateOf avoids the boxing and clears the lint failure. Generated-By: PostHog Code Task-Id: b89cbdd1-9f16-4fa4-b3d0-3f9b268b0c2b
The previous commit removed the mutableStateOf import while switching the question index to mutableIntStateOf, but the nullable rating state at SurveySheet.kt:189 (mutableStateOf<Int?>(null)) still needs the boxed variant since mutableIntStateOf does not support nullable Int. Generated-By: PostHog Code Task-Id: b89cbdd1-9f16-4fa4-b3d0-3f9b268b0c2b
AGP aborts the build when lint is configured with a baseline file that doesn't exist on disk (it generates one and exits to force a check-in). Matching the empty placeholder convention used by posthog-android/. Generated-By: PostHog Code Task-Id: b89cbdd1-9f16-4fa4-b3d0-3f9b268b0c2b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Closes the long-standing gap in #102 (open since Feb 2024): the Android SDK's default surveys delegate is a stub that only logs. Customers using surveys on Android have to implement their own UI, which is a significant lift.
Driven by large customer (20+ global apps), who are blocked rolling out post-print NPS surveys on Android. iOS shipped a complete SwiftUI implementation in PostHog/posthog-ios#320 — this PR ports the same pattern to Kotlin/Compose as an opt-in module so non-Compose apps don't pay for it.
What's in this PR
:posthog-android-surveys-compose— Material 3ModalBottomSheet+ Jetpack ComposePostHogDisplaySurveyAppearance— background, submit button, text, border, rating-button colors all pull through, plus a faithful port of the iOS hex / CSS-color name parser (140-entry table)onSurveyShown/onSurveyResponse/onSurveyClosedfire at the right moments so the SDK'ssurvey shown/survey sent/survey dismissedevents fire correctly. The delegate never callsPostHog.capturedirectly.ComposeViewinjected into the foreground Activity'sandroid.R.id.contentvia anActivityLifecycleCallbacks-backedActivityProvider— works on any Activity type (noFragmentActivityrequirement)@Previewcomposables forSurveySheet/NumberRating/BottomSectionin default and themed appearancesTrigger test surveybutton capturingshow_test_survey, delegate set inMyApp.ktWhat's NOT in this PR (planned follow-ups)
displayThankYouMessage == truepath)Architecture decisions
:posthog-android, no changes to:posthogor:posthog-android) — non-Compose apps don't pay APK-size cost. Mirrors the AndroidX optional-Compose-module pattern.1.0.0-alpha01— lets this module iterate through alphas without dragging core SDK versions. Module added tobinary-compatibility-validatorignoredProjectsduring alpha.2024.12.01(matches the sample app's existing pin), Material 31.3.1,kotlin.plugin.composefor K2-era Compose.rememberModalBottomSheetState(confirmValueChange = { it != SheetValue.Hidden })for the "X-button-only dismissal" — matches iOSinteractiveDismissDisabled()semantics with one line instead of a customSheetState.consumer-rules.pro+-keep PostHogSurveysComposeDelegate— minimal consumer-side ProGuard surface; populate if downstream minified builds ever surface issues.@file-levelktlint_function_naming_ignore_when_annotated_with = Composablein module.editorconfigso PascalCase@Composablefunctions don't trip thestandard:function-namingrule.Local verification
This is what I ran in my dev env (no Android emulator available there, so the visual checks are deferred to a real device run):
./gradlew spotlessCheck— passes./gradlew detekt— passes./gradlew :posthog:build— passes (confirming no regression in core):posthog-android-surveys-compose:assembleDebug,:posthog-android-surveys-compose:lint, full./gradlew build) deferred to CI here because my dev env doesn't have the Android SDKManual test plan (for me to run on an emulator before un-drafting)
show_test_survey, set custom background/submit colors so theming is visiblesurvey sentwith the right rating, X-button firessurvey dismissed, swipe-down is ignoredReviewers
cc @marandaneto @ioannisj @lucasheriques
Will also link the Feb 2026 internal Slack thread on Android surveys in a comment.
Refs #102