Skip to content

Commit 7fbbd23

Browse files
author
root1234
committed
Improve bottom AI assistant Codex profile manager
1 parent cea0c19 commit 7fbbd23

File tree

10 files changed

+805
-32
lines changed

10 files changed

+805
-32
lines changed

core/app/src/main/java/com/tom/rv2ide/artificial/dialogs/CodexCliConfigDialog.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import kotlinx.coroutines.launch
2424
class CodexCliConfigDialog(
2525
private val profileId: String? = null,
2626
private val createNew: Boolean = false,
27+
private val makeActiveOnSave: Boolean = true,
2728
private val onSave: (CodexCliSettings) -> Unit
2829
) : BottomSheetDialogFragment() {
2930

@@ -315,7 +316,7 @@ class CodexCliConfigDialog(
315316
contextWindow = contextWindow ?: return,
316317
autoCompactTokenLimit = autoCompact ?: return,
317318
cachedModels = buildSuggestedModels(model, reviewModel),
318-
makeActive = true
319+
makeActive = makeActiveOnSave
319320
)
320321
onSave(savedProfile.toSettings())
321322
dismiss()

core/app/src/main/java/com/tom/rv2ide/artificial/dialogs/CodexProfileManagerDialog.kt

Lines changed: 403 additions & 0 deletions
Large diffs are not rendered by default.

core/app/src/main/java/com/tom/rv2ide/fragments/assistant/AIAssistantConsoleFragment.kt

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import com.tom.rv2ide.artificial.agents.custom.CustomProviderProfile
3232
import com.tom.rv2ide.artificial.agents.external.CodexCliConfig
3333
import com.tom.rv2ide.artificial.agents.external.CodexTermuxBridge
3434
import com.tom.rv2ide.artificial.dialogs.CodexCliConfigDialog
35+
import com.tom.rv2ide.artificial.dialogs.CodexProfileManagerDialog
36+
import com.tom.rv2ide.artificial.dialogs.CodexProfileManagerEvent
3537
import com.tom.rv2ide.artificial.dialogs.CustomProviderConfigDialog
3638
import com.tom.rv2ide.utils.ProjectHelper.getProjectRoot
3739
import java.io.File
@@ -200,11 +202,7 @@ class AIAssistantConsoleFragment : Fragment() {
200202
}
201203

202204
engineButton.setOnClickListener {
203-
when (Agents(requireContext()).getProvider()) {
204-
"external" -> openCodexConfig(selectAfterSave = false)
205-
"custom" -> openCustomProviderConfig(selectAfterSave = false)
206-
else -> showProviderSwitcher()
207-
}
205+
showEngineSettingsMenu()
208206
}
209207

210208
slashButton.setOnClickListener {
@@ -240,6 +238,14 @@ class AIAssistantConsoleFragment : Fragment() {
240238
}
241239
}
242240

241+
private fun showEngineSettingsMenu() {
242+
when (Agents(requireContext()).getProvider()) {
243+
"external" -> showCodexSettingsMenu()
244+
"custom" -> openCustomProviderConfig(selectAfterSave = false)
245+
else -> showProviderSwitcher()
246+
}
247+
}
248+
243249
private fun bindUiState() {
244250
viewLifecycleOwner.lifecycleScope.launch {
245251
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -383,22 +389,126 @@ class AIAssistantConsoleFragment : Fragment() {
383389
}
384390
}
385391

386-
private fun openCodexConfig(selectAfterSave: Boolean) {
387-
CodexCliConfigDialog {
388-
CodexTermuxBridge.ensureManagedPreset(context = requireContext())
389-
val applied = consoleViewModel.applyAgentSelection(
390-
providerId = "external",
391-
preferredModel = CodexCliConfig.getModelId()
392-
)
392+
private fun showCodexSettingsMenu() {
393+
CodexProfileManagerDialog(::handleCodexProfileManagerEvent)
394+
.show(parentFragmentManager, "CodexProfileManagerDialog")
395+
}
396+
397+
private fun handleCodexProfileManagerEvent(event: CodexProfileManagerEvent) {
398+
when (event) {
399+
is CodexProfileManagerEvent.Activated -> {
400+
if (applyActiveCodexProfileSelection()) {
401+
showSnackbar(getString(R.string.ai_assistant_codex_profile_active, event.profileName))
402+
} else {
403+
showSnackbar(
404+
getString(
405+
R.string.ai_assistant_no_valid_api_key,
406+
providerDisplayName("external")
407+
)
408+
)
409+
}
410+
}
411+
412+
is CodexProfileManagerEvent.Saved -> {
413+
if (event.profileBecameActive) {
414+
if (applyActiveCodexProfileSelection()) {
415+
showSnackbar(getString(R.string.ai_assistant_codex_profile_active, event.profileName))
416+
} else {
417+
showSnackbar(
418+
getString(
419+
R.string.ai_assistant_no_valid_api_key,
420+
providerDisplayName("external")
421+
)
422+
)
423+
}
424+
} else {
425+
showSnackbar(getString(R.string.ai_assistant_codex_profile_saved, event.profileName))
426+
}
427+
}
428+
429+
is CodexProfileManagerEvent.Deleted -> {
430+
if (!event.affectedActiveProfile) {
431+
showSnackbar(getString(R.string.ai_assistant_deleted_profile, event.profileName))
432+
return
433+
}
434+
435+
val newActiveProfile = CodexCliConfig.getActiveProfile()
436+
when {
437+
newActiveProfile != null -> {
438+
if (applyActiveCodexProfileSelection()) {
439+
showSnackbar(
440+
getString(
441+
R.string.ai_assistant_codex_profile_active,
442+
newActiveProfile.name
443+
)
444+
)
445+
} else {
446+
showSnackbar(
447+
getString(
448+
R.string.ai_assistant_no_valid_api_key,
449+
providerDisplayName("external")
450+
)
451+
)
452+
}
453+
}
454+
455+
CodexCliConfig.hasValidConfig() -> {
456+
if (applyActiveCodexProfileSelection()) {
457+
showSnackbar(getString(R.string.ai_assistant_deleted_profile, event.profileName))
458+
} else {
459+
showSnackbar(
460+
getString(
461+
R.string.ai_assistant_no_valid_api_key,
462+
providerDisplayName("external")
463+
)
464+
)
465+
}
466+
}
467+
468+
else -> {
469+
showSnackbar(getString(R.string.ai_assistant_codex_profile_deleted_requires_reselect))
470+
}
471+
}
472+
}
473+
}
474+
}
475+
476+
private fun applyActiveCodexProfileSelection(): Boolean {
477+
CodexTermuxBridge.ensureManagedPreset(context = requireContext())
478+
return consoleViewModel.applyAgentSelection(
479+
providerId = "external",
480+
preferredModel = CodexCliConfig.getModelId()
481+
)
482+
}
483+
484+
private fun openCodexConfig(
485+
profileId: String? = CodexCliConfig.getActiveProfileId().takeIf { it.isNotBlank() },
486+
createNew: Boolean = false,
487+
selectAfterSave: Boolean
488+
) {
489+
CodexCliConfigDialog(
490+
profileId = profileId,
491+
createNew = createNew,
492+
makeActiveOnSave = selectAfterSave
493+
) { savedSettings ->
494+
val activeProfileSaved = savedSettings.profileId.isNotBlank() &&
495+
savedSettings.profileId == CodexCliConfig.getActiveProfileId()
496+
val applied = if (activeProfileSaved) {
497+
applyActiveCodexProfileSelection()
498+
} else {
499+
false
500+
}
393501
if (applied && selectAfterSave) {
394502
showSnackbar(
395503
getString(
396504
R.string.ai_assistant_switched_to_provider,
397505
providerDisplayName("external")
398506
)
399507
)
508+
} else if (activeProfileSaved && applied) {
509+
showSnackbar(getString(R.string.ai_assistant_codex_profile_active, savedSettings.resolvedProfileName))
400510
} else {
401-
showSnackbar(getString(R.string.ai_assistant_codex_settings_saved))
511+
showSnackbar(getString(R.string.ai_assistant_codex_profile_saved, savedSettings.resolvedProfileName))
402512
}
403513
}.show(parentFragmentManager, "CodexCliConfigDialog")
404514
}

core/app/src/main/res/layout/dialog_codex_cli_config.xml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@
3535
android:layout_width="match_parent"
3636
android:layout_height="wrap_content"
3737
android:layout_marginBottom="12dp"
38-
android:hint="@string/ai_assistant_codex_profile_name_hint">
38+
android:hint="@string/ai_assistant_codex_profile_name_hint"
39+
app:placeholderText="@string/ai_assistant_codex_profile_name_example">
3940

4041
<com.google.android.material.textfield.TextInputEditText
4142
android:id="@+id/codexProfileNameInput"
4243
android:layout_width="match_parent"
4344
android:layout_height="wrap_content"
44-
android:inputType="text"
45-
android:hint="@string/ai_assistant_codex_profile_name_example" />
45+
android:inputType="text" />
4646

4747
</com.google.android.material.textfield.TextInputLayout>
4848

@@ -52,14 +52,14 @@
5252
android:layout_width="match_parent"
5353
android:layout_height="wrap_content"
5454
android:layout_marginBottom="12dp"
55-
android:hint="@string/ai_assistant_codex_provider_id_hint">
55+
android:hint="@string/ai_assistant_codex_provider_id_hint"
56+
app:placeholderText="@string/ai_assistant_codex_provider_id_example">
5657

5758
<com.google.android.material.textfield.TextInputEditText
5859
android:id="@+id/codexProviderIdInput"
5960
android:layout_width="match_parent"
6061
android:layout_height="wrap_content"
61-
android:inputType="textNoSuggestions"
62-
android:hint="@string/ai_assistant_codex_provider_id_example" />
62+
android:inputType="textNoSuggestions" />
6363

6464
</com.google.android.material.textfield.TextInputLayout>
6565

@@ -69,14 +69,14 @@
6969
android:layout_width="match_parent"
7070
android:layout_height="wrap_content"
7171
android:layout_marginBottom="12dp"
72-
android:hint="@string/ai_assistant_codex_provider_name_hint">
72+
android:hint="@string/ai_assistant_codex_provider_name_hint"
73+
app:placeholderText="@string/ai_assistant_codex_provider_name_example">
7374

7475
<com.google.android.material.textfield.TextInputEditText
7576
android:id="@+id/codexProviderNameInput"
7677
android:layout_width="match_parent"
7778
android:layout_height="wrap_content"
78-
android:inputType="text"
79-
android:hint="@string/ai_assistant_codex_provider_name_example" />
79+
android:inputType="text" />
8080

8181
</com.google.android.material.textfield.TextInputLayout>
8282

@@ -86,14 +86,14 @@
8686
android:layout_width="match_parent"
8787
android:layout_height="wrap_content"
8888
android:layout_marginBottom="12dp"
89-
android:hint="@string/ai_assistant_base_url_hint">
89+
android:hint="@string/ai_assistant_base_url_hint"
90+
app:placeholderText="@string/ai_assistant_base_url_example">
9091

9192
<com.google.android.material.textfield.TextInputEditText
9293
android:id="@+id/codexBaseUrlInput"
9394
android:layout_width="match_parent"
9495
android:layout_height="wrap_content"
95-
android:inputType="textUri"
96-
android:hint="@string/ai_assistant_base_url_example" />
96+
android:inputType="textUri" />
9797

9898
</com.google.android.material.textfield.TextInputLayout>
9999

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="match_parent"
5+
android:orientation="vertical"
6+
android:paddingStart="16dp"
7+
android:paddingTop="12dp"
8+
android:paddingEnd="16dp"
9+
android:paddingBottom="12dp">
10+
11+
<TextView
12+
android:layout_width="match_parent"
13+
android:layout_height="wrap_content"
14+
android:text="@string/ai_assistant_codex_profile_manager_title"
15+
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
16+
android:textStyle="bold" />
17+
18+
<TextView
19+
android:layout_width="match_parent"
20+
android:layout_height="wrap_content"
21+
android:layout_marginTop="4dp"
22+
android:layout_marginBottom="10dp"
23+
android:text="@string/ai_assistant_codex_profile_manager_summary"
24+
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
25+
android:textColor="?attr/colorOutline" />
26+
27+
<androidx.recyclerview.widget.RecyclerView
28+
android:id="@+id/codexProfileManagerRecyclerView"
29+
android:layout_width="match_parent"
30+
android:layout_height="0dp"
31+
android:layout_weight="1"
32+
android:clipToPadding="false"
33+
android:nestedScrollingEnabled="true"
34+
android:overScrollMode="ifContentScrolls"
35+
android:paddingBottom="8dp" />
36+
37+
</LinearLayout>

core/app/src/main/res/layout/dialog_custom_provider_config.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@
3535
android:layout_height="wrap_content"
3636
android:hint="@string/ai_assistant_custom_provider_profile_name_hint"
3737
android:layout_marginBottom="16dp"
38-
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
38+
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
39+
app:placeholderText="@string/ai_assistant_custom_provider_profile_name_example">
3940

4041
<com.google.android.material.textfield.TextInputEditText
4142
android:id="@+id/profileNameInput"
4243
android:layout_width="match_parent"
4344
android:layout_height="wrap_content"
44-
android:inputType="textPersonName"
45-
android:hint="@string/ai_assistant_custom_provider_profile_name_example" />
45+
android:inputType="textPersonName" />
4646

4747
</com.google.android.material.textfield.TextInputLayout>
4848

@@ -52,14 +52,14 @@
5252
android:layout_height="wrap_content"
5353
android:hint="@string/ai_assistant_base_url_hint"
5454
android:layout_marginBottom="16dp"
55-
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
55+
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
56+
app:placeholderText="@string/ai_assistant_base_url_example">
5657

5758
<com.google.android.material.textfield.TextInputEditText
5859
android:id="@+id/baseUrlInput"
5960
android:layout_width="match_parent"
6061
android:layout_height="wrap_content"
61-
android:inputType="textUri"
62-
android:hint="@string/ai_assistant_base_url_example" />
62+
android:inputType="textUri" />
6363

6464
</com.google.android.material.textfield.TextInputLayout>
6565

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:layout_marginTop="6dp"
7+
android:layout_marginBottom="6dp"
8+
app:cardBackgroundColor="?attr/colorSurfaceContainerLow"
9+
app:cardCornerRadius="20dp"
10+
app:cardElevation="0dp"
11+
app:strokeColor="?attr/colorPrimary"
12+
app:strokeWidth="1dp">
13+
14+
<LinearLayout
15+
android:layout_width="match_parent"
16+
android:layout_height="wrap_content"
17+
android:gravity="center_vertical"
18+
android:orientation="horizontal"
19+
android:paddingStart="16dp"
20+
android:paddingTop="16dp"
21+
android:paddingEnd="16dp"
22+
android:paddingBottom="16dp">
23+
24+
<TextView
25+
android:layout_width="40dp"
26+
android:layout_height="40dp"
27+
android:background="?attr/colorPrimaryContainer"
28+
android:gravity="center"
29+
android:text="+"
30+
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
31+
android:textColor="?attr/colorOnPrimaryContainer"
32+
android:textStyle="bold" />
33+
34+
<LinearLayout
35+
android:layout_width="0dp"
36+
android:layout_height="wrap_content"
37+
android:layout_marginStart="14dp"
38+
android:layout_weight="1"
39+
android:orientation="vertical">
40+
41+
<TextView
42+
android:id="@+id/codexProfileAddTitle"
43+
android:layout_width="match_parent"
44+
android:layout_height="wrap_content"
45+
android:textAppearance="@style/TextAppearance.Material3.TitleSmall"
46+
android:textColor="?attr/colorOnSurface"
47+
android:textStyle="bold" />
48+
49+
<TextView
50+
android:id="@+id/codexProfileAddSummary"
51+
android:layout_width="match_parent"
52+
android:layout_height="wrap_content"
53+
android:layout_marginTop="4dp"
54+
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
55+
android:textColor="?attr/colorOnSurfaceVariant" />
56+
57+
</LinearLayout>
58+
59+
</LinearLayout>
60+
61+
</com.google.android.material.card.MaterialCardView>

0 commit comments

Comments
 (0)