Skip to content

Conversation

@calren
Copy link
Collaborator

@calren calren commented Aug 1, 2025

No description provided.

google-labs-jules bot and others added 2 commits August 1, 2025 20:34
This commit refactors the GenAIImageDescription sample to use a `UiState` sealed class in the `GenAIImageDescriptionViewModel`. This improves the state management and provides a better user experience by showing the status of the feature, including download progress.

The changes are based on the implementation of the GenAISummarization sample.
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @calren, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the GenAI Image Description and GenAI Summarization sample applications to implement a more robust and reactive UI state management system. By introducing a comprehensive UiState sealed class, the samples now offer detailed feedback to users throughout the AI model's lifecycle, from feature availability checks and download progress to content generation and error handling. This change not only enhances the user experience with clearer status indications but also improves the maintainability and architectural clarity of the sample code.

Highlights

  • Unified UI State Management: Introduced a sealed class UiState for both the GenAI Image Description and GenAI Summarization samples, providing a structured way to represent various stages of AI model interaction (initial, checking status, downloading, generating, success, error).
  • Enhanced User Feedback: The UI now dynamically updates to show granular progress and status, such as feature download progress (bytes downloaded/total bytes) and specific error messages, significantly improving the user experience.
  • Improved ViewModel Architecture: Both ViewModel implementations were migrated to AndroidViewModel to properly handle Application context, and the logic was refactored to manage the new UiState flow, including cancellation of ongoing operations.
  • Dependency Updates: Added androidx.lifecycle.runtime.compose to both sample build.gradle.kts files to support collectAsStateWithLifecycle for lifecycle-aware state collection.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the GenAI Image Description sample to use a UI state holder, which is a great architectural improvement. The changes align well with modern Android development practices like Unidirectional Data Flow.

My review includes a few suggestions to further improve the code:

  • Adhering more closely to the repository's style guide regarding AndroidViewModel.
  • Improving the safety of state updates by making them atomic to prevent potential race conditions and crashes.
  • Removing a piece of unreachable code for better clarity.

These changes will make the sample more robust and a better reference for developers.

@calren calren requested a review from bentrengrove August 1, 2025 21:03
if (uiState !is GenAIImageDescriptionUiState.Initial) {
val bottomSheetText = when (val state = uiState) {
is GenAIImageDescriptionUiState.DownloadingFeature -> stringResource(
id = R.string.genai_image_description_downloading,
Copy link
Collaborator

@ksemenova ksemenova Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I see that this string doesn't accept any params:
    "Downloading feature"

  • Should we use "image_desc_downloading" instead?
    Downloading feature: %1$d / %2$d
    And it looks like image_desc_downloading is never used.

  • Also maybe the string should be: "Downloading: %1$d of %2$d bytes"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, this should have been using image_desc_downloading, fixed

) : GenAIImageDescriptionUiState()

private var imageDescriber: ImageDescriber? = null
data class Generating(val generatedOutput: String) : GenAIImageDescriptionUiState()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we show generatedOutput during generation?
If yes, then maybe we can combine Generating and Success states into one? And then the generatedOutput string would have a single home.

Copy link
Member

@bentrengrove bentrengrove Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case it is fine to have them in both states, because one is partial and one is complete so it is conceivable that the text UI might look different, you would also want to show that the generation is still in progress with a loading indicator. You could name them something different to make that more clear, maybe just partialOutput in generating

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to partialOutput here


override fun onDownloadProgress(bytesDownloaded: Long) {
_uiState.update {
(it as? GenAIImageDescriptionUiState.DownloadingFeature)?.copy(bytesDownloaded = bytesDownloaded) ?: it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I could test this somehow, but I don't think the download actually gets cancelled by the coroutine. That means this might still fire and mess with your UI state after you have set it back to initial from dismissing the bottom sheet.

The easiest way to fix is just to not support cancellation and remove the bottom sheet

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay yeah i tested it, it gets really wonky if i hide the bottom sheet while it's still downloading.

removed the bottom sheet implementation

) : GenAIImageDescriptionUiState()

private var imageDescriber: ImageDescriber? = null
data class Generating(val generatedOutput: String) : GenAIImageDescriptionUiState()
Copy link
Member

@bentrengrove bentrengrove Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case it is fine to have them in both states, because one is partial and one is complete so it is conceivable that the text UI might look different, you would also want to show that the generation is still in progress with a loading indicator. You could name them something different to make that more clear, maybe just partialOutput in generating

@calren
Copy link
Collaborator Author

calren commented Aug 7, 2025

thanks everybody for the review!

addressed ben and kate's comments, so this is ready for another round of review

Copy link
Member

@bentrengrove bentrengrove left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor question but LGTM

Comment on lines 133 to 136
fun clearResult() {
_uiState.value = GenAIImageDescriptionUiState.Initial
imageDescriptionJob?.cancel()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need this function? If you do, you still have the same bug

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, good call, removed

@calren calren merged commit e869e79 into main Aug 8, 2025
1 check passed
@calren calren deleted the refactor/genai-image-description-mvvm branch August 8, 2025 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants