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.YouTubeExerciseScreen
|
||||
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.SettingsRoutes
|
||||
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)
|
||||
val mainTabRoutes = setOf(
|
||||
Screen.Home.route,
|
||||
Screen.Library.route,
|
||||
Screen.Stats.route,
|
||||
Screen.Translation.route,
|
||||
Screen.Vocabulary.route,
|
||||
@@ -132,6 +134,10 @@ fun AppNavHost(
|
||||
StatsScreen(navController = navController)
|
||||
}
|
||||
|
||||
composable(Screen.Library.route) {
|
||||
LibraryScreen(navController = navController)
|
||||
}
|
||||
|
||||
composable("start_exercise") {
|
||||
StartExerciseScreen(navController = navController)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ sealed class Screen(
|
||||
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 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 More : Screen("more", R.string.label_more, AppIcons.MoreVert, AppIcons.MoreVert)
|
||||
object Dictionary : Screen("dictionary", R.string.label_dictionary, AppIcons.DictionaryFilled, AppIcons.DictionaryOutlined)
|
||||
@@ -81,12 +82,13 @@ sealed class Screen(
|
||||
|
||||
companion object {
|
||||
fun getAllScreens(showExperimental: Boolean = false): List<Screen> {
|
||||
return listOf(Home, Vocabulary, Stats)
|
||||
return listOf(Home, Library, Stats)
|
||||
}
|
||||
|
||||
fun getMoreMenuItems(showExperimental: Boolean = false): List<Screen> {
|
||||
val items = mutableListOf<Screen>()
|
||||
items.add(Translation)
|
||||
items.add(Vocabulary) // Legacy vocabulary moved to More
|
||||
items.add(Dictionary)
|
||||
items.add(Settings)
|
||||
if (showExperimental) {
|
||||
|
||||
@@ -1,12 +1,56 @@
|
||||
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.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.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.Slider
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
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.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
|
||||
|
||||
@Composable
|
||||
@@ -16,11 +60,373 @@ fun StartExerciseScreen(
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
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 = title.uppercase(),
|
||||
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 = "Start Exercise Screen",
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
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_error">Oops, something went wrong :(</string>
|
||||
<string name="label_stats">Stats</string>
|
||||
<string name="label_library">Library</string>
|
||||
<string name="label_legacy_vocabulary">Legacy Vocabulary</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user