Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ class GeminiPlugin : IPlugin, DocumentationExtension {
does by embedding every chunk of the project with this model. It
is a separate setting because no Gemini model does both: this list
holds the models that advertise <code>embedContent</code>, and the
<b>Gemini Model</b> list above holds those that advertise
<b>Model</b> list above holds those that advertise
<code>generateContent</code>.</p>
<p>Changing it changes the vector space, so the project is indexed
again from scratch. Vectors from two different models are not
Expand Down

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions plugins/AI-Agent-Gemini/src/main/res/drawable/ic_dropdown.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M7,10l5,5 5,-5z" />
</vector>
137 changes: 118 additions & 19 deletions plugins/AI-Agent-Gemini/src/main/res/layout/fragment_gemini_settings.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Material fields and buttons throughout, on the shared house spacing scale, so this pane and the
OpenAI one read as the same screen with a different backend behind it. The root android:theme is
what guarantees the plugin's own button/input styles win over whatever theme the host builds the
inflation Context from.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:orientation="vertical"
android:theme="@style/ThemeOverlay.Plugin">

<!-- API key. Collapses to the status line once a key is stored. -->

<TextView
android:id="@+id/gemini_api_key_status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginBottom="@dimen/space_sm"
android:textAppearance="@style/Plugin.Text.Body"
android:visibility="gone" />

<LinearLayout
Expand All @@ -20,11 +29,11 @@
android:orientation="vertical">

<TextView
android:id="@+id/gemini_api_key_label"
style="@style/Plugin.SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/label_gemini_api_key"
android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingBottom="4dp"/>
android:text="@string/label_gemini_api_key" />

<!--
The reveal toggle is the box's own end icon rather than the loose ImageButton that used to
Expand Down Expand Up @@ -53,52 +62,142 @@

<TextView
android:id="@+id/gemini_key_verification_text"
style="@style/Plugin.StatusLine"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawablePadding="6dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginTop="@dimen/space_sm"
android:visibility="gone" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="@dimen/space_md"
android:orientation="horizontal">

<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_clear_api_key"
style="@style/PluginButton.Filled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/btn_clear_api_key"
android:visibility="gone" />

<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_edit_api_key"
style="@style/PluginButton.Filled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginStart="@dimen/space_sm"
android:layout_weight="1"
android:text="@string/btn_edit_api_key"
android:visibility="gone" />

<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_save_api_key"
style="@style/PluginButton.Filled"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/btn_save_api_key" />

</LinearLayout>

<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_get_free_key"
style="@style/PluginButton.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginTop="@dimen/space_sm"
android:text="@string/btn_get_free_key" />

<!-- Model. One dropdown, the same control the OpenAI pane uses: the catalog is whatever the
key can reach, so the list is the only way to change it. The chevron is not declared here —
Material 1.10 never reads app:endIconDrawable, so the icon a layout asks for draws blank;
setupDropdownEndIcon() sets it on every box in code. -->

<TextView
android:id="@+id/gemini_model_label"
style="@style/Plugin.SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_xl"
android:text="@string/label_gemini_model" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/gemini_model_box"
style="@style/PluginTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_gemini_model"
app:endIconContentDescription="@string/cd_show_models"
app:endIconMode="custom">

<AutoCompleteTextView
android:id="@+id/gemini_model_input"
style="@style/PluginTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="0"
android:inputType="none"
android:maxLines="1"
Comment thread
jatezzz marked this conversation as resolved.
Outdated
android:popupBackground="@color/plugin_surface" />
</com.google.android.material.textfield.TextInputLayout>

<TextView
android:id="@+id/gemini_model_hint_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_xs"
android:text="@string/hint_gemini_model_help"
android:textAppearance="@style/Plugin.Text.Small" />

<!-- Embedding model. The other half of the same catalog: semantic search embeds with this one,
never with the chat model above. -->

<TextView
android:id="@+id/gemini_embedding_model_label"
style="@style/Plugin.SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_xl"
android:text="@string/label_gemini_embedding_model" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/gemini_embedding_model_box"
style="@style/PluginTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_gemini_embedding_model"
app:endIconContentDescription="@string/cd_show_embedding_models"
app:endIconMode="custom">

<AutoCompleteTextView
android:id="@+id/gemini_embedding_model_input"
style="@style/PluginTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="0"
android:inputType="none"
android:maxLines="1"
android:popupBackground="@color/plugin_surface" />
</com.google.android.material.textfield.TextInputLayout>

<TextView
android:id="@+id/gemini_embedding_model_hint_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_xs"
android:text="@string/hint_gemini_embedding_model_help"
android:textAppearance="@style/Plugin.Text.Small" />

<!-- One Refresh for both pickers: a single catalog walk fills both lists. -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_refresh_models"
style="@style/PluginButton.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/space_md"
android:text="@string/refresh_models" />

</LinearLayout>
15 changes: 15 additions & 0 deletions plugins/AI-Agent-Gemini/src/main/res/layout/item_dropdown.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
One row of the model dropdown. The plugin's own item layout rather than
android.R.layout.simple_list_item_1, whose text color comes from the framework theme in effect
when the popup window is built — which is not reliably the one the pane is drawn in.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/touch_target_min"
android:paddingHorizontal="@dimen/space_lg"
android:paddingVertical="@dimen/space_md"
android:textAppearance="@style/Plugin.Text.Body" />
22 changes: 22 additions & 0 deletions plugins/AI-Agent-Gemini/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Spacing, radius and type scale shared with the other CoGo house plugins (see
client-time-tracker), so this pane sits on the same grid as the rest of the IDE's plugin UI
instead of the ad-hoc 4/8/24dp margins it used before.
-->
<resources>
<dimen name="space_xs">4dp</dimen>
<dimen name="space_sm">8dp</dimen>
<dimen name="space_md">12dp</dimen>
<dimen name="space_lg">16dp</dimen>
<dimen name="space_xl">24dp</dimen>

<dimen name="radius_md">8dp</dimen>
<dimen name="radius_lg">12dp</dimen>
Comment thread
jatezzz marked this conversation as resolved.
Outdated

<dimen name="text_micro">11sp</dimen>
<dimen name="text_small">13sp</dimen>
<dimen name="text_body">15sp</dimen>

<dimen name="touch_target_min">48dp</dimen>
</resources>
15 changes: 11 additions & 4 deletions plugins/AI-Agent-Gemini/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<string name="gemini_error_failed_reason">The Gemini request failed. %1$s</string>

<!-- Settings pane this backend contributes (see GeminiSettingsFragment) -->
<string name="label_gemini_api_key">Gemini API Key</string>
<string name="label_gemini_api_key">API Key</string>
<string name="hint_gemini_api_key">Enter your Gemini API key</string>
<!-- Reveal toggle on the masked credential field. Deliberately the same wording in
every AI plugin: one control, one announcement, whatever the field holds. -->
Expand Down Expand Up @@ -51,9 +51,16 @@
<string name="msg_key_hint_edit_first">Copied a new key? Tap Edit, then paste it into the field.</string>
<string name="msg_no_browser_for_key">No browser available. The link was copied — open it on another device: %s</string>
<string name="msg_key_link_copy_failed">Couldn\'t open a browser. Get your key at %s</string>
<string name="label_gemini_model">Gemini Model</string>
<string name="label_gemini_embedding_model">Gemini Embedding Model</string>
<string name="current_model">Current: %s</string>
<string name="label_gemini_model">Model</string>
<string name="hint_gemini_model">Gemini model</string>
<string name="cd_show_models">Show the model list</string>
<string name="hint_gemini_model_help">Refresh to list the models your key can reach.</string>
<string name="hint_gemini_model_live">Tap to pick from the models this key can reach.</string>
<string name="label_gemini_embedding_model">Embedding Model</string>
<string name="hint_gemini_embedding_model">Gemini embedding model</string>
<string name="cd_show_embedding_models">Show the embedding model list</string>
<string name="hint_gemini_embedding_model_help">Used by semantic search, never for chat. Refresh to list the embedding models your key can reach.</string>
<string name="hint_gemini_embedding_model_live">Tap to pick from the embedding models this key can reach.</string>
<string name="refresh_models">Refresh Models</string>
<string name="loading">Loading…</string>
<string name="model_changed">Model changed to %s</string>
Expand Down
85 changes: 85 additions & 0 deletions plugins/AI-Agent-Gemini/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,85 @@
<item name="colorOnError">@color/plugin_on_error</item>
<item name="colorErrorContainer">@color/plugin_error_container</item>
<item name="colorOnErrorContainer">@color/plugin_on_error_container</item>

<item name="materialButtonStyle">@style/PluginButton.Filled</item>
<item name="textInputStyle">@style/PluginTextInputLayout</item>
</style>

<!--
ThemeOverlay applied via android:theme on the settings pane's root. The host may build the
plugin's inflation Context by layering PluginTheme onto the *activity's* theme without
forcing it (PluginResourceContext), in which case PluginTheme's own items lose and the pane
falls back to framework widget defaults. android:theme on a ViewGroup wraps that subtree's
inflation Context, which is where MaterialButton and TextInputLayout look their styles up, so
this is what guarantees the pane is styled either way. No colors here: the widget styles pin
their own, so nothing depends on which theme won.
-->
<style name="ThemeOverlay.Plugin" parent="">
<item name="materialButtonStyle">@style/PluginButton.Filled</item>
<item name="textInputStyle">@style/PluginTextInputLayout</item>
</style>

<!-- Typography -->

<style name="Plugin.Text.Body" parent="TextAppearance.Material3.BodyMedium">
<item name="android:textColor">@color/plugin_on_surface</item>
<item name="android:textSize">@dimen/text_body</item>
</style>

<style name="Plugin.Text.Small" parent="TextAppearance.Material3.BodySmall">
<item name="android:textColor">@color/plugin_text_muted</item>
<item name="android:textSize">@dimen/text_small</item>
<item name="android:lineSpacingMultiplier">1.25</item>
</style>

<!-- Eyebrow label above a field, as used by the IDE's own grouped settings. -->
<style name="Plugin.Text.Label" parent="TextAppearance.Material3.LabelMedium">
<item name="android:textColor">@color/plugin_text_muted</item>
<item name="android:textSize">@dimen/text_micro</item>
<item name="android:textAllCaps">true</item>
<item name="android:letterSpacing">0.08</item>
<item name="android:fontFamily">sans-serif-medium</item>
</style>

<!-- Explicit parent="" required: dot-name inference would look up @style/Plugin, which does
not exist, and break resource linking. -->
<style name="Plugin.SectionHeader" parent="">
<item name="android:textAppearance">@style/Plugin.Text.Label</item>
<item name="android:paddingBottom">@dimen/space_xs</item>
</style>

<!-- A status line under a field: one icon, one sentence, muted. -->
<style name="Plugin.StatusLine" parent="">
<item name="android:textAppearance">@style/Plugin.Text.Small</item>
<item name="android:drawablePadding">@dimen/space_sm</item>
<item name="android:gravity">center_vertical</item>
</style>

<!-- Buttons. Every color is a direct @color/* reference, never ?attr/*: the host may build the
plugin's inflation theme by layering PluginTheme onto the activity's own without forcing
it, and a Material 3 widget whose color roles resolve against that theme comes out as an
unreadable slab — dark-on-dark for an outlined button in light mode. The palette is neutral
by choice, matching the IDE's own grey accent rather than this plugin's orange, on a screen
whose chrome belongs to AI Core. Light/dark comes from values-night/colors.xml.

One style for every button on the pane: a secondary action that styled itself differently
is exactly what broke on the OpenAI pane, and the hierarchy is not worth a second way to
get contrast wrong. -->
<style name="PluginButton.Filled" parent="Widget.Material3.Button">
<item name="android:textAllCaps">false</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:letterSpacing">0</item>
<item name="cornerRadius">@dimen/radius_md</item>
<item name="android:minHeight">@dimen/touch_target_min</item>
<item name="android:textColor">@color/plugin_on_secondary</item>
<item name="backgroundTint">@color/plugin_secondary</item>
<item name="iconTint">@color/plugin_on_secondary</item>
<item name="rippleColor">@color/plugin_ripple</item>
</style>

<!-- Inputs -->

<!--
The API key box, styled by an explicit style= on the widget rather than through the theme's
textInputStyle: the host may build this plugin's inflation Context by layering PluginTheme
Expand All @@ -47,9 +124,17 @@
<item name="hintTextColor">@color/plugin_text_muted</item>
<item name="android:textColorHint">@color/plugin_text_muted</item>
<item name="endIconTint">@color/plugin_on_surface_variant</item>
<item name="boxCornerRadiusTopStart">@dimen/radius_md</item>
<item name="boxCornerRadiusTopEnd">@dimen/radius_md</item>
<item name="boxCornerRadiusBottomStart">@dimen/radius_md</item>
<item name="boxCornerRadiusBottomEnd">@dimen/radius_md</item>
</style>

<!-- The text inside every box. Applied explicitly because the model field is an
AutoCompleteTextView rather than a TextInputEditText, and so does not pick the box's own
text style up from the theme. -->
<style name="PluginTextInputEditText" parent="Widget.Material3.TextInputEditText.OutlinedBox">
<item name="android:textAppearance">@style/Plugin.Text.Body</item>
<item name="android:textColor">@color/plugin_on_surface</item>
</style>

Expand Down
Loading
Loading