implement LibraryScreen, migrate Vocabulary to legacy, and refactor StartExerciseScreen UI
This commit is contained in:
@@ -30,6 +30,7 @@ import eu.gaudian.translator.view.exercises.StartExerciseScreen
|
|||||||
import eu.gaudian.translator.view.exercises.YouTubeBrowserScreen
|
import eu.gaudian.translator.view.exercises.YouTubeBrowserScreen
|
||||||
import eu.gaudian.translator.view.exercises.YouTubeExerciseScreen
|
import eu.gaudian.translator.view.exercises.YouTubeExerciseScreen
|
||||||
import eu.gaudian.translator.view.home.HomeScreen
|
import eu.gaudian.translator.view.home.HomeScreen
|
||||||
|
import eu.gaudian.translator.view.library.LibraryScreen
|
||||||
import eu.gaudian.translator.view.settings.DictionaryOptionsScreen
|
import eu.gaudian.translator.view.settings.DictionaryOptionsScreen
|
||||||
import eu.gaudian.translator.view.settings.SettingsRoutes
|
import eu.gaudian.translator.view.settings.SettingsRoutes
|
||||||
import eu.gaudian.translator.view.settings.TranslationSettingsScreen
|
import eu.gaudian.translator.view.settings.TranslationSettingsScreen
|
||||||
@@ -61,6 +62,7 @@ fun AppNavHost(
|
|||||||
// 1. Define your Main Tab "Leaf" Routes (the actual start destinations of your graphs)
|
// 1. Define your Main Tab "Leaf" Routes (the actual start destinations of your graphs)
|
||||||
val mainTabRoutes = setOf(
|
val mainTabRoutes = setOf(
|
||||||
Screen.Home.route,
|
Screen.Home.route,
|
||||||
|
Screen.Library.route,
|
||||||
Screen.Stats.route,
|
Screen.Stats.route,
|
||||||
Screen.Translation.route,
|
Screen.Translation.route,
|
||||||
Screen.Vocabulary.route,
|
Screen.Vocabulary.route,
|
||||||
@@ -132,6 +134,10 @@ fun AppNavHost(
|
|||||||
StatsScreen(navController = navController)
|
StatsScreen(navController = navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(Screen.Library.route) {
|
||||||
|
LibraryScreen(navController = navController)
|
||||||
|
}
|
||||||
|
|
||||||
composable("start_exercise") {
|
composable("start_exercise") {
|
||||||
StartExerciseScreen(navController = navController)
|
StartExerciseScreen(navController = navController)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ sealed class Screen(
|
|||||||
object Home : Screen("home", R.string.label_home, AppIcons.Home, AppIcons.Home)
|
object Home : Screen("home", R.string.label_home, AppIcons.Home, AppIcons.Home)
|
||||||
object Stats : Screen("stats", R.string.label_stats, AppIcons.Statistics, AppIcons.Statistics)
|
object Stats : Screen("stats", R.string.label_stats, AppIcons.Statistics, AppIcons.Statistics)
|
||||||
object Translation : Screen("translation", R.string.label_translation, AppIcons.TranslateFilled, AppIcons.TranslateOutlined)
|
object Translation : Screen("translation", R.string.label_translation, AppIcons.TranslateFilled, AppIcons.TranslateOutlined)
|
||||||
object Vocabulary : Screen("vocabulary", R.string.label_vocabulary, AppIcons.VocabularyFilled, AppIcons.VocabularyOutlined)
|
object Library : Screen("library", R.string.label_library, AppIcons.VocabularyFilled, AppIcons.VocabularyOutlined)
|
||||||
|
object Vocabulary : Screen("vocabulary", R.string.label_legacy_vocabulary, AppIcons.VocabularyFilled, AppIcons.VocabularyOutlined)
|
||||||
object Settings : Screen("settings", R.string.title_settings, AppIcons.SettingsFilled, AppIcons.SettingsOutlined)
|
object Settings : Screen("settings", R.string.title_settings, AppIcons.SettingsFilled, AppIcons.SettingsOutlined)
|
||||||
object More : Screen("more", R.string.label_more, AppIcons.MoreVert, AppIcons.MoreVert)
|
object More : Screen("more", R.string.label_more, AppIcons.MoreVert, AppIcons.MoreVert)
|
||||||
object Dictionary : Screen("dictionary", R.string.label_dictionary, AppIcons.DictionaryFilled, AppIcons.DictionaryOutlined)
|
object Dictionary : Screen("dictionary", R.string.label_dictionary, AppIcons.DictionaryFilled, AppIcons.DictionaryOutlined)
|
||||||
@@ -81,12 +82,13 @@ sealed class Screen(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getAllScreens(showExperimental: Boolean = false): List<Screen> {
|
fun getAllScreens(showExperimental: Boolean = false): List<Screen> {
|
||||||
return listOf(Home, Vocabulary, Stats)
|
return listOf(Home, Library, Stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMoreMenuItems(showExperimental: Boolean = false): List<Screen> {
|
fun getMoreMenuItems(showExperimental: Boolean = false): List<Screen> {
|
||||||
val items = mutableListOf<Screen>()
|
val items = mutableListOf<Screen>()
|
||||||
items.add(Translation)
|
items.add(Translation)
|
||||||
|
items.add(Vocabulary) // Legacy vocabulary moved to More
|
||||||
items.add(Dictionary)
|
items.add(Dictionary)
|
||||||
items.add(Settings)
|
items.add(Settings)
|
||||||
if (showExperimental) {
|
if (showExperimental) {
|
||||||
|
|||||||
@@ -1,12 +1,56 @@
|
|||||||
package eu.gaudian.translator.view.exercises
|
package eu.gaudian.translator.view.exercises
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
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.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
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.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
|
import androidx.compose.material.icons.filled.CheckCircle
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material.icons.filled.Hearing
|
||||||
|
import androidx.compose.material.icons.filled.List
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
|
import androidx.compose.material.icons.outlined.Circle
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Slider
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -16,11 +60,373 @@ fun StartExerciseScreen(
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.TopCenter
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.widthIn(max = 700.dp) // Keeps it from over-stretching on tablets
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
TopBarSection(onBackClick = { navController.popBackStack() })
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(horizontal = 24.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(32.dp)
|
||||||
|
) {
|
||||||
|
item { Spacer(modifier = Modifier.height(8.dp)) }
|
||||||
|
item { LanguagePairSection() }
|
||||||
|
item { CategoriesSection() }
|
||||||
|
item { DifficultySection() }
|
||||||
|
item { NumberOfCardsSection() }
|
||||||
|
item { QuestionTypesSection() }
|
||||||
|
item { Spacer(modifier = Modifier.height(24.dp)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomButtonSection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TopBarSection(onBackClick: () -> Unit) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onBackClick,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBackIosNew,
|
||||||
|
contentDescription = "Back",
|
||||||
|
modifier = Modifier.size(18.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Start Exercise",
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = androidx.compose.ui.text.style.TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
// Spacer to balance the back button for centering
|
||||||
|
Spacer(modifier = Modifier.size(48.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SectionHeader(title: String, actionText: String? = null, onActionClick: () -> Unit = {}) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Start Exercise Screen",
|
text = title.uppercase(),
|
||||||
style = MaterialTheme.typography.headlineMedium
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
letterSpacing = 1.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
if (actionText != null) {
|
||||||
|
Text(
|
||||||
|
text = actionText,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.clickable { onActionClick() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LanguagePairSection() {
|
||||||
|
var selectedPair by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
SectionHeader(title = "Language Pair", actionText = "Change")
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
|
LanguageChip(
|
||||||
|
text = "EN → ES",
|
||||||
|
isSelected = selectedPair == 0,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = { selectedPair = 0 }
|
||||||
|
)
|
||||||
|
LanguageChip(
|
||||||
|
text = "EN → FR",
|
||||||
|
isSelected = selectedPair == 1,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = { selectedPair = 1 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LanguageChip(text: String, isSelected: Boolean, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||||
|
Surface(
|
||||||
|
modifier = modifier.height(56.dp),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) else MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
border = if (isSelected) BorderStroke(2.dp, MaterialTheme.colorScheme.primary) else null,
|
||||||
|
onClick = onClick
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
// Dummy overlapping flags
|
||||||
|
Box(modifier = Modifier.width(32.dp)) {
|
||||||
|
Box(modifier = Modifier.size(20.dp).clip(CircleShape).background(Color.Red).align(Alignment.CenterStart))
|
||||||
|
Box(modifier = Modifier.size(20.dp).clip(CircleShape).background(Color.Blue).align(Alignment.CenterEnd))
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(text = text, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun CategoriesSection() {
|
||||||
|
val categories = listOf("Travel", "Business", "Food", "Technology", "Slang", "Academic", "Relationships")
|
||||||
|
var selectedCategories by remember { mutableStateOf(setOf("Travel", "Food")) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
SectionHeader(title = "Categories")
|
||||||
|
FlowRow(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
categories.forEach { category ->
|
||||||
|
val isSelected = selectedCategories.contains(category)
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(20.dp),
|
||||||
|
color = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
onClick = {
|
||||||
|
selectedCategories = if (isSelected) selectedCategories - category else selectedCategories + category
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = category,
|
||||||
|
color = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DifficultySection() {
|
||||||
|
val difficulties = listOf("Easy", "Medium", "Hard")
|
||||||
|
var selectedDifficulty by remember { mutableStateOf("Medium") }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
SectionHeader(title = "Difficulty Level")
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(50),
|
||||||
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
modifier = Modifier.fillMaxWidth().height(56.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxSize().padding(4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
difficulties.forEach { level ->
|
||||||
|
val isSelected = selectedDifficulty == level
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.clip(RoundedCornerShape(50))
|
||||||
|
.background(if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent)
|
||||||
|
.clickable { selectedDifficulty = level },
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = level,
|
||||||
|
color = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NumberOfCardsSection() {
|
||||||
|
var sliderPosition by remember { mutableFloatStateOf(25f) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "NUMBER OF CARDS",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
letterSpacing = 1.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = sliderPosition.toInt().toString(),
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
value = sliderPosition,
|
||||||
|
onValueChange = { sliderPosition = it },
|
||||||
|
valueRange = 5f..50f,
|
||||||
|
steps = 45
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text("5 CARDS", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
|
Text("50 CARDS", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun QuestionTypesSection() {
|
||||||
|
var selectedTypes by remember { mutableStateOf(setOf("Multiple Choice", "Spelling")) }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
SectionHeader(title = "Question Types")
|
||||||
|
|
||||||
|
QuestionTypeCard(
|
||||||
|
title = "Multiple Choice",
|
||||||
|
subtitle = "Choose the correct meaning",
|
||||||
|
icon = Icons.Default.List,
|
||||||
|
isSelected = selectedTypes.contains("Multiple Choice"),
|
||||||
|
onClick = {
|
||||||
|
selectedTypes = if (selectedTypes.contains("Multiple Choice")) selectedTypes - "Multiple Choice" else selectedTypes + "Multiple Choice"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
QuestionTypeCard(
|
||||||
|
title = "Spelling",
|
||||||
|
subtitle = "Type the translated word",
|
||||||
|
icon = Icons.Default.Edit,
|
||||||
|
isSelected = selectedTypes.contains("Spelling"),
|
||||||
|
onClick = {
|
||||||
|
selectedTypes = if (selectedTypes.contains("Spelling")) selectedTypes - "Spelling" else selectedTypes + "Spelling"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
QuestionTypeCard(
|
||||||
|
title = "Listening",
|
||||||
|
subtitle = "Recognize spoken words",
|
||||||
|
icon = Icons.Default.Hearing,
|
||||||
|
isSelected = selectedTypes.contains("Listening"),
|
||||||
|
onClick = {
|
||||||
|
selectedTypes = if (selectedTypes.contains("Listening")) selectedTypes - "Listening" else selectedTypes + "Listening"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun QuestionTypeCard(title: String, subtitle: String, icon: ImageVector, isSelected: Boolean, onClick: () -> Unit) {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
color = if (isSelected) MaterialTheme.colorScheme.primary.copy(alpha = 0.05f) else MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
border = if (isSelected) BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.5f)) else null,
|
||||||
|
onClick = onClick
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(40.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(MaterialTheme.colorScheme.surface),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(imageVector = icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(text = title, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyLarge)
|
||||||
|
Text(text = subtitle, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
|
}
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isSelected) Icons.Default.CheckCircle else Icons.Outlined.Circle,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BottomButtonSection() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(24.dp)
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = { /* TODO: Start Session */ },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(56.dp),
|
||||||
|
shape = RoundedCornerShape(28.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Start Session",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.PlayArrow,
|
||||||
|
contentDescription = "Play",
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package eu.gaudian.translator.view.library
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LibraryScreen(
|
||||||
|
navController: NavHostController,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Library Screen",
|
||||||
|
style = MaterialTheme.typography.headlineMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1116,4 +1116,6 @@
|
|||||||
<string name="message_test_success">This is a test success message!</string>
|
<string name="message_test_success">This is a test success message!</string>
|
||||||
<string name="message_test_error">Oops, something went wrong :(</string>
|
<string name="message_test_error">Oops, something went wrong :(</string>
|
||||||
<string name="label_stats">Stats</string>
|
<string name="label_stats">Stats</string>
|
||||||
|
<string name="label_library">Library</string>
|
||||||
|
<string name="label_legacy_vocabulary">Legacy Vocabulary</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user