Skip to content

Conversation

@jacobsimionato
Copy link
Collaborator

@jacobsimionato jacobsimionato commented Aug 1, 2025

Changes:

  • Model Switching UI:
    • Added an overflow menu to the travel_app's AppBar allowing users to switch between "Gemini Flash" and "Gemini Pro"
      models.
    • The currently selected model is indicated with a tick box in the menu.
    • Refactored AiClient to use a ValueNotifier for reactive model switching, improving type safety and
      centralizing model name management.

Fixes: #28

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 introduces a model switching capability in the travel app, allowing users to choose between Gemini Flash and Pro. The implementation correctly uses a ValueNotifier for reactive UI updates. My review includes a high-severity fix to ensure the ValueNotifier instance is immutable to prevent listener issues, and a suggestion to refactor the UI code for better maintainability by reducing duplication.

///
/// Defaults to 'gemini-2.5-flash'.
final String model;
ValueNotifier<GeminiModel> model;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The model field should be final. A public, non-final field for a ValueNotifier allows the entire notifier instance to be replaced from outside the class. This is risky because any widgets listening to the original notifier instance would stop receiving updates, leading to a broken UI state. The ValueNotifier instance itself should be immutable after creation; only its internal value should change via model.value = ..., which the switchModel method correctly does.

  final ValueNotifier<GeminiModel> model;

Comment on lines 132 to 153
itemBuilder: (BuildContext context) => <PopupMenuEntry<GeminiModel>>[
PopupMenuItem<GeminiModel>(
value: GeminiModel.flash,
child: Row(
children: [
Text('Gemini Flash'),
if (currentModel == GeminiModel.flash)
const Icon(Icons.check),
],
),
),
PopupMenuItem<GeminiModel>(
value: GeminiModel.pro,
child: Row(
children: [
Text('Gemini Pro'),
if (currentModel == GeminiModel.pro)
const Icon(Icons.check),
],
),
),
],
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The code for creating PopupMenuItems is duplicated for each model. This can be made more concise and maintainable by iterating over GeminiModel.values. This avoids repetition and makes it easier to add new models in the future.

For even cleaner code, you could add a displayName property to the GeminiModel enum in pkgs/flutter_genui/lib/src/ai_client/ai_client.dart and use it here instead of the conditional logic for the text.

                itemBuilder: (BuildContext context) => [
                  for (final model in GeminiModel.values)
                    PopupMenuItem<GeminiModel>(
                      value: model,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(model == GeminiModel.flash ? 'Gemini Flash' : 'Gemini Pro'),
                          if (currentModel == model) const Icon(Icons.check),
                        ],
                      ),
                    ),
                ],

@jacobsimionato jacobsimionato requested a review from polina-c August 4, 2025 02:45
@jacobsimionato jacobsimionato merged commit 735bd98 into main Aug 5, 2025
4 checks passed
@jacobsimionato jacobsimionato deleted the model_selector_2 branch September 28, 2025 21:51
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.

We probably want a model selector in the sample app: Pro or Flash

2 participants