Build a Compose Rating Card
OpenAIAndroid Engineer · Technical ScreenLast updated
Tests proficiency in modern Android development with Kotlin and Jetpack Compose, focusing on unidirectional data flow (UDF), custom stateless composables, ViewModel state management, and asynchronous submission handling.
Problem Description
Design and implement an interactive Feedback Rating Card in Android using Jetpack Compose and Kotlin. The component allows users to select a 1-to-5 star rating, enter an optional feedback comment, and submit the feedback to a backend repository.
Your solution should follow modern Android architecture patterns, specifically Unidirectional Data Flow (UDF) with an MVVM structure.
Requirements
-
Stateless
StarRatingBarComposable:- Accepts
rating: Int(0 to 5, where 0 means unselected),maxStars: Int = 5, and anonRatingChanged: (Int) -> Unitcallback. - Renders
maxStarsinteractive icons (e.g., filled star for active, outlined star for inactive). - Clicking star
kupdates the rating tok.
- Accepts
-
RatingCardScreen Composable:- Displays the
StarRatingBar. - Displays a text field for an optional comment (maximum 280 characters). Show a character counter:
"{current}/{max}". - Displays a "Submit" button:
- Disabled if
rating == 0or if character count exceeds 280, or while submission is in progress.
- Disabled if
- Handles submission UI states:
- Loading: Show a
CircularProgressIndicatorinstead of/inside the submit button. - Success: Replace the card content with a "Thank you for your feedback!" confirmation view and a "Reset" action.
- Error: Show an inline error banner or Snackbar message with a retry option.
- Loading: Show a
- Displays the
-
State Management (
RatingViewModel):- Expose a single immutable
StateFlow. - Handle actions:
setRating(Int),updateComment(String),submit(), andreset(). - Simulate an asynchronous submission call via a suspend function (e.g.,
delay(1000)).
- Expose a single immutable
Expected Interfaces
data class RatingUiState(
val rating: Int = 0,
val comment: String = "",
val submissionStatus: SubmissionStatus = SubmissionStatus.Idle,
val errorMessage: String? = null
) {
val isValid: Boolean
get() = rating in 1..5 && comment.length <= 280
}
sealed interface SubmissionStatus {
object Idle : SubmissionStatus
object Loading : SubmissionStatus
object Success : SubmissionStatus
object Error : SubmissionStatus
}
@Composable
fun StarRatingBar(
rating: Int,
onRatingChanged: (Int) -> Unit,
modifier: Modifier = Modifier,
maxStars: Int = 5
)
@Composable
fun RatingCardScreen(
viewModel: RatingViewModel = viewModel(),
modifier: Modifier = Modifier
)
Edge Cases to Consider
- Rapid clicks on the submit button before the asynchronous call resolves (double submission).
- Configuration changes (e.g., screen rotation) must preserve the user's draft rating and comment without re-triggering network requests.
- Pasting text longer than 280 characters should either be truncated or highlight validation errors appropriately.
Hints
Hint 1
Separate stateful container composables from stateless presentation composables to keep components testable and reusable.
Hint 2
Use a Kotlin `sealed interface` for UI submission states and expose UI state via `StateFlow` collected with `collectAsStateWithLifecycle()`.
Hint 3
Prevent concurrent submissions by checking `submissionStatus !is SubmissionStatus.Loading` before launching the submission coroutine in the ViewModel.
Follow-up questions
- How would you support half-star increments or smooth drag-to-rate gestures in the `StarRatingBar` composable?
- How would you ensure accessibility compliance (e.g., TalkBack content descriptions and custom accessibility actions for star selection)?
- How would you write automated UI tests for this screen using Compose UI testing APIs (`createComposeRule`)?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.