Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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 @@ -157,12 +157,13 @@ enum class ModelProvider {

companion object {
fun from(id: String, providerString: String?): ModelProvider {
val provider = providerString?.lowercase()
return when {
id.startsWith("meta-llama/") || id.startsWith("meta-llama_") || providerString == "azure" -> META
id.startsWith("mistralai/") || id.startsWith("mistralai_") || providerString == "mistral" -> MISTRAL
id.contains("gpt-oss") -> OSS
providerString == "anthropic" -> ANTHROPIC
providerString == "openai" -> OPENAI
id.startsWith("meta-llama/") || id.startsWith("meta-llama_") || provider == "azure" -> META
id.startsWith("mistralai/") || id.startsWith("mistralai_") || provider == "mistral" -> MISTRAL
id.contains("gpt-oss") || id.startsWith("tinfoil/") || provider == "tinfoil" -> OSS
provider == "anthropic" -> ANTHROPIC
provider == "openai" -> OPENAI
else -> UNKNOWN
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,15 @@ class ModelPickerView @JvmOverloads constructor(
addView(item)
}

private fun PopupMenuItemView.setLeadingIcon(@DrawableRes iconRes: Int?) {
private fun PopupMenuItemView.setLeadingIcon(@DrawableRes iconRes: Int) {
val label = findViewById<DaxTextView>(com.duckduckgo.mobile.android.R.id.label) ?: return
label.maxLines = 1
label.isSingleLine = true
label.ellipsize = TextUtils.TruncateAt.END
label.setPaddingRelative(label.paddingStart, label.paddingTop, 0, label.paddingBottom)
val drawable = iconRes?.let { AppCompatResources.getDrawable(context, it) }
val drawable = AppCompatResources.getDrawable(context, iconRes)
label.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null)
label.compoundDrawablePadding = if (drawable != null) {
resources.getDimensionPixelSize(com.duckduckgo.mobile.android.R.dimen.keyline_2)
} else {
0
}
label.compoundDrawablePadding = resources.getDimensionPixelSize(com.duckduckgo.mobile.android.R.dimen.keyline_2)
}

private fun PopupMenuItemView.configureTrailingIcon() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,13 @@ class ModelPickerViewModel @Inject constructor(
}

@DrawableRes
fun getIconResForModel(model: AIChatModel): Int? = when (model.provider) {
fun getIconResForModel(model: AIChatModel): Int = when (model.provider) {
ModelProvider.OPENAI -> R.drawable.ic_ai_model_openai_16
ModelProvider.ANTHROPIC -> R.drawable.ic_ai_model_claude_16
ModelProvider.MISTRAL -> R.drawable.ic_ai_model_mistral_16
ModelProvider.META -> R.drawable.ic_ai_model_llama_16
ModelProvider.OSS -> R.drawable.ic_ai_model_oss_16
ModelProvider.UNKNOWN -> null
// OSS doubles as the fallback for unrecognised providers so a model never renders without an icon.
ModelProvider.OSS, ModelProvider.UNKNOWN -> R.drawable.ic_ai_model_oss_16
}

private fun List<AIChatModel>.toSectionOrNull(@StringRes headerRes: Int?): ModelSection? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,31 @@ class ModelProviderTest {
assertEquals(ModelProvider.UNKNOWN, ModelProvider.from("gpt-5-mini", providerString = null))
}

@Test
fun whenProviderIsTinfoilThenOss() {
assertEquals(ModelProvider.OSS, ModelProvider.from("tinfoil/gemma4-31b", providerString = "tinfoil"))
}

@Test
fun whenIdHasTinfoilSlashPrefixAndProviderMissingThenOss() {
assertEquals(ModelProvider.OSS, ModelProvider.from("tinfoil/gemma4-31b", providerString = null))
}

@Test
fun whenProviderIsTinfoilCapitalisedThenOss() {
assertEquals(ModelProvider.OSS, ModelProvider.from("gemma-3n-e4b-it", providerString = "Tinfoil"))
}

@Test
fun whenProviderIsCapitalisedOpenAiThenOpenAi() {
assertEquals(ModelProvider.OPENAI, ModelProvider.from("gpt-5-mini", providerString = "OpenAI"))
}

@Test
fun whenProviderIsCapitalisedAnthropicThenAnthropic() {
assertEquals(ModelProvider.ANTHROPIC, ModelProvider.from("claude-3-5-sonnet", providerString = "Anthropic"))
}

@Test
fun whenProviderIsUnknownStringThenUnknown() {
assertEquals(ModelProvider.UNKNOWN, ModelProvider.from("some-id", providerString = "perplexity"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,10 +503,10 @@ class ModelPickerViewModelTest {
}

@Test
fun whenModelProviderIsUnknownThenNoIcon() {
fun whenModelProviderIsUnknownThenOssIconFallback() {
val model = freeModel(id = "some-other-model", shortName = "Other", provider = ModelProvider.UNKNOWN)

assertNull(testee.getIconResForModel(model))
assertEquals(R.drawable.ic_ai_model_oss_16, testee.getIconResForModel(model))
}

@Test
Expand Down
Loading