update providers_config.json models and refactor IntroFlow.kt UI

This commit is contained in:
jonasgaudian
2026-02-15 20:53:21 +01:00
parent f4fcffe90a
commit 7d18f8eb04
4 changed files with 103 additions and 106 deletions

View File

@@ -4,7 +4,7 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-02-15T16:58:18.944420200Z"> <DropdownSelection timestamp="2026-02-15T17:06:55.070074900Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\jonas\.android\avd\Pixel_Tablet.avd" /> <DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\jonas\.android\avd\Pixel_Tablet.avd" />

View File

@@ -58,17 +58,17 @@
"websiteUrl": "https://platform.openai.com/", "websiteUrl": "https://platform.openai.com/",
"isCustom": false, "isCustom": false,
"models": [ "models": [
{
"modelId": "gpt-5.2",
"displayName": "GPT-5.2",
"provider": "openai",
"description": "Balanced performance with enhanced reasoning and creativity."
},
{ {
"modelId": "gpt-5.1-instant", "modelId": "gpt-5.1-instant",
"displayName": "GPT-5.1 Instant", "displayName": "GPT-5.1 Instant",
"provider": "openai", "provider": "openai",
"description": "The standard high-speed efficiency model replacing older 'Nano' tiers." "description": "The standard high-speed efficiency model replacing older 'Nano' tiers."
},
{
"modelId": "gpt-5-nano",
"displayName": "GPT-5 Nano",
"provider": "openai",
"description": "Fast and cheap model sufficient for most tasks."
} }
] ]
}, },
@@ -120,15 +120,15 @@
"key": "gemini", "key": "gemini",
"displayName": "Google Gemini", "displayName": "Google Gemini",
"baseUrl": "https://generativelanguage.googleapis.com/", "baseUrl": "https://generativelanguage.googleapis.com/",
"endpoint": "v1beta/models/gemini-3-flash-preview:generateContent", "endpoint": "v1beta/models/gemini-2.5-pro:generateContent",
"websiteUrl": "https://ai.google/", "websiteUrl": "https://ai.google/",
"isCustom": false, "isCustom": false,
"models": [ "models": [
{ {
"modelId": "gemini-3-flash-preview", "modelId": "gemini-2.5-pro",
"displayName": "Gemini 3 Flash", "displayName": "Gemini 2.5 Pro",
"provider": "gemini", "provider": "gemini",
"description": "Current default: Massive context, grounded, and extremely fast." "description": "Stable release: State-of-the-art reasoning with 1M context."
}, },
{ {
"modelId": "gemini-3-pro-preview", "modelId": "gemini-3-pro-preview",
@@ -155,12 +155,6 @@
"websiteUrl": "https://groq.com/", "websiteUrl": "https://groq.com/",
"isCustom": false, "isCustom": false,
"models": [ "models": [
{
"modelId": "llama-4-scout-17b",
"displayName": "Llama 4 Scout",
"provider": "groq",
"description": "Powerful Llama 4 model running at extreme speed."
},
{ {
"modelId": "meta-llama/llama-4-maverick", "modelId": "meta-llama/llama-4-maverick",
"displayName": "Llama 4 Maverick", "displayName": "Llama 4 Maverick",
@@ -216,10 +210,10 @@
"description": "World's fastest inference (2000+ tokens/sec) on Wafer-Scale Engines." "description": "World's fastest inference (2000+ tokens/sec) on Wafer-Scale Engines."
}, },
{ {
"modelId": "llama3.1-8b", "modelId": "llama-4-scout",
"displayName": "Llama 3.1 8B", "displayName": "Llama 4 Scout",
"provider": "cerebras", "provider": "cerebras",
"description": "Instant speed for simple tasks." "description": "High-quality 17B active param model running at 2,600 tokens/sec."
} }
] ]
}, },
@@ -238,10 +232,10 @@
"description": "Hosted via the Hugging Face serverless router (Free tier limits apply)." "description": "Hosted via the Hugging Face serverless router (Free tier limits apply)."
}, },
{ {
"modelId": "microsoft/Phi-3.5-mini-instruct", "modelId": "Qwen/Qwen2.5-72B-Instruct",
"displayName": "Phi 3.5 Mini", "displayName": "Qwen 2.5 72B",
"provider": "huggingface", "provider": "huggingface",
"description": "Highly capable small model from Microsoft." "description": "High-quality open model with excellent reasoning and multilingual capabilities."
} }
] ]
} }

View File

@@ -5,11 +5,9 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -42,81 +40,88 @@ import eu.gaudian.translator.view.composable.AppIcons
import eu.gaudian.translator.view.composable.PrimaryButton import eu.gaudian.translator.view.composable.PrimaryButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
fun IntroNavHost(onIntroFinished: () -> Unit) { fun IntroNavHost(onIntroFinished: () -> Unit) {
val pages = listOf( val pages = listOf(
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_welcome), title = stringResource(R.string.intro_title_welcome),
description = stringResource(R.string.intro_desc_welcome), description = stringResource(R.string.intro_desc_welcome),
content = { IconContent(iconRes = R.drawable.ic_intro_welcome) } content = { IconContent(iconRes = R.drawable.ic_intro_welcome) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_ai_assistant), title = stringResource(R.string.intro_title_ai_assistant),
description = stringResource(R.string.intro_desc_ai_assistant), description = stringResource(R.string.intro_desc_ai_assistant),
content = { content = {
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(4.dp)) { Column(
IconContent(iconRes = R.drawable.ic_intro_ai_agents) horizontalAlignment = Alignment.CenterHorizontally,
FlowRow(horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally), verticalArrangement = Arrangement.spacedBy(2.dp), modifier = Modifier.fillMaxWidth()) { verticalArrangement = Arrangement.spacedBy(4.dp)
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_mistral)) }) ) {
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_your_own_ai)) }) IconContent(iconRes = R.drawable.ic_intro_ai_agents)
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_openai)) }) FlowRow(
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_claude)) }) horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally),
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_gemini)) }) verticalArrangement = Arrangement.spacedBy(2.dp),
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_deepseek)) }) modifier = Modifier.fillMaxWidth()
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_openrouter)) }) ) {
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_and_many_more)) }) SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_mistral)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_your_own_ai)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_openai)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_claude)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_gemini)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_deepseek)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_openrouter)) })
SuggestionChip(onClick = { }, label = { Text(stringResource(R.string.text_and_many_more)) })
} }
} }
} }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_dictionary_translator), title = stringResource(R.string.intro_title_dictionary_translator),
description = stringResource(R.string.intro_desc_dictionary_translator), description = stringResource(R.string.intro_desc_dictionary_translator),
content = { IconContent(iconRes = R.drawable.ic_intro_lookup) } content = { IconContent(iconRes = R.drawable.ic_intro_lookup) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_flashcards), title = stringResource(R.string.intro_title_flashcards),
description = stringResource(R.string.intro_desc_flashcards), description = stringResource(R.string.intro_desc_flashcards),
content = { FlashcardTopicsPreview() } content = { FlashcardTopicsPreview() }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_practice), title = stringResource(R.string.intro_title_practice),
description = stringResource(R.string.intro_desc_practice), description = stringResource(R.string.intro_desc_practice),
content = { IconContent(iconRes = R.drawable.ic_inro_practice) } content = { IconContent(iconRes = R.drawable.ic_inro_practice) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_learning_journey), title = stringResource(R.string.intro_title_learning_journey),
description = stringResource(R.string.intro_desc_learning_journey), description = stringResource(R.string.intro_desc_learning_journey),
content = { IconContent(iconRes = R.drawable.ic_intro_learning_journey)} content = { IconContent(iconRes = R.drawable.ic_intro_learning_journey) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_categories), title = stringResource(R.string.intro_title_categories),
description = stringResource(R.string.intro_desc_categories), description = stringResource(R.string.intro_desc_categories),
content = { IconContent(iconRes = R.drawable.ic_intro_categories) } content = { IconContent(iconRes = R.drawable.ic_intro_categories) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_progress), title = stringResource(R.string.intro_title_progress),
description = stringResource(R.string.intro_desc_progress), description = stringResource(R.string.intro_desc_progress),
content = { IconContent(iconRes = R.drawable.ic_intro_track_progress) } content = { IconContent(iconRes = R.drawable.ic_intro_track_progress) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_need_help), title = stringResource(R.string.intro_need_help),
description = stringResource(R.string.intro_if_you_need_help_you), description = stringResource(R.string.intro_if_you_need_help_you),
content = { IconContent(iconRes = R.drawable.ic_intro_help) } content = { IconContent(iconRes = R.drawable.ic_intro_help) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_beta), title = stringResource(R.string.intro_title_beta),
description = stringResource(R.string.intro_desc_beta), description = stringResource(R.string.intro_desc_beta),
content = { IconContent(iconRes = R.drawable.ic_icon_construction) } content = { IconContent(iconRes = R.drawable.ic_icon_construction) }
), ),
IntroPageData( IntroPageData(
title = stringResource(R.string.intro_title_all_set), title = stringResource(R.string.intro_title_all_set),
description = stringResource(R.string.intro_desc_all_set), description = stringResource(R.string.intro_desc_all_set),
content = { IconContent(iconRes = R.drawable.ic_intro_robot) } content = { IconContent(iconRes = R.drawable.ic_intro_robot) }
)
) )
)
val pagerState = rememberPagerState(pageCount = { pages.size }) val pagerState = rememberPagerState(pageCount = { pages.size })
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -128,7 +133,6 @@ fun IntroNavHost(onIntroFinished: () -> Unit) {
.statusBarsPadding() .statusBarsPadding()
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {
// Full-width Skip intro button aligned to end but sized like primary (fillMaxWidth)
eu.gaudian.translator.view.composable.SecondaryButton( eu.gaudian.translator.view.composable.SecondaryButton(
onClick = { onIntroFinished() }, onClick = { onIntroFinished() },
text = stringResource(R.string.intro_skip), text = stringResource(R.string.intro_skip),
@@ -145,7 +149,9 @@ fun IntroNavHost(onIntroFinished: () -> Unit) {
) { ) {
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
modifier = Modifier.weight(1f) modifier = Modifier
.fillMaxWidth()
.weight(1f)
) { pageIndex -> ) { pageIndex ->
IntroPage(pageData = pages[pageIndex]) IntroPage(pageData = pages[pageIndex])
} }
@@ -170,7 +176,7 @@ fun IntroNavHost(onIntroFinished: () -> Unit) {
} }
}, },
text = if (pagerState.currentPage < pages.size - 1) stringResource(R.string.next) else stringResource(R.string.get_started), text = if (pagerState.currentPage < pages.size - 1) stringResource(R.string.next) else stringResource(R.string.get_started),
icon = if (pagerState.currentPage < pages.size - 1)AppIcons.ArrowForwardNoChevron else null, icon = if (pagerState.currentPage < pages.size - 1) AppIcons.ArrowForwardNoChevron else null,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
} }
@@ -189,9 +195,9 @@ private fun IntroPage(pageData: IntroPageData) {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(24.dp, Alignment.CenterVertically), verticalArrangement = Arrangement.spacedBy(24.dp, Alignment.CenterVertically),
modifier = Modifier modifier = Modifier
.fillMaxHeight() .fillMaxSize() // Fixed: This was previously fillMaxHeight()
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState()) // Allow scrolling for larger hint content .verticalScroll(rememberScrollState())
) { ) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text( Text(
@@ -234,15 +240,14 @@ private fun PagerIndicator(pageCount: Int, currentPage: Int) {
@Composable @Composable
private fun IconContent(iconRes: Int) { private fun IconContent(iconRes: Int) {
Box(modifier = Modifier.clip(RoundedCornerShape(16.dp))) { Box(modifier = Modifier.clip(RoundedCornerShape(16.dp))) {
Icon( Icon(
painter = painterResource(id = iconRes), painter = painterResource(id = iconRes),
contentDescription = null, contentDescription = null,
tint = Color.Unspecified, tint = Color.Unspecified,
modifier = Modifier.size(250.dp) modifier = Modifier.size(250.dp)
) )
}
} }
}
@Composable @Composable
private fun FlashcardTopicsPreview() { private fun FlashcardTopicsPreview() {

View File

@@ -6,7 +6,6 @@ import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -391,7 +390,6 @@ private fun ExerciseTypeSelector(
onTypeSelected: (VocabularyExerciseType) -> Unit, onTypeSelected: (VocabularyExerciseType) -> Unit,
) { ) {
// Using FlowRow for a more flexible layout that wraps to the next line if needed // Using FlowRow for a more flexible layout that wraps to the next line if needed
@OptIn(ExperimentalLayoutApi::class)
FlowRow( FlowRow(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally),