diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1254ca1..964c563 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,17 +32,6 @@
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/eu/gaudian/translator/CorrectActivity.kt b/app/src/main/java/eu/gaudian/translator/CorrectActivity.kt
deleted file mode 100644
index c730db2..0000000
--- a/app/src/main/java/eu/gaudian/translator/CorrectActivity.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-@file:Suppress("HardCodedStringLiteral")
-
-package eu.gaudian.translator
-
-import android.content.Intent
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.compose.material3.Text
-import androidx.compose.ui.res.stringResource
-import eu.gaudian.translator.utils.Log
-
-class CorrectActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- val intent = intent
- val action = intent.action
- val type = intent.type
-
- if (Intent.ACTION_SEND == action && type == "text/plain") {
- val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
- if (sharedText != null) {
- Log.d("EditActivity", "Received text: $sharedText")
- setContent {
- Text(stringResource(R.string.editing_text, sharedText))
-
- }
- } else {
- Log.e("EditActivity", getString(R.string.no_text_received))
- setContent {
- Text(stringResource(R.string.error_no_text_to_edit))
- }
- }
- } else {
- Log.d("EditActivity", "Not launched with ACTION_SEND")
- setContent {
- Text(stringResource(R.string.not_launched_with_text_to_edit))
- }
- }
-
- }
-
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/eu/gaudian/translator/view/Navigation.kt b/app/src/main/java/eu/gaudian/translator/view/Navigation.kt
index 019fe95..40e86b5 100644
--- a/app/src/main/java/eu/gaudian/translator/view/Navigation.kt
+++ b/app/src/main/java/eu/gaudian/translator/view/Navigation.kt
@@ -28,6 +28,7 @@ import eu.gaudian.translator.view.exercises.ExerciseSessionScreen
import eu.gaudian.translator.view.exercises.MainExerciseScreen
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.settings.DictionaryOptionsScreen
import eu.gaudian.translator.view.settings.SettingsRoutes
import eu.gaudian.translator.view.settings.TranslationSettingsScreen
@@ -57,8 +58,8 @@ fun AppNavHost(
// 1. Define your Main Tab "Leaf" Routes (the actual start destinations of your graphs)
val mainTabRoutes = setOf(
- Screen.Home.route, // "home" or "main_translation" depending on which one you actually navigate to
- "main_translation",
+ Screen.Home.route,
+ Screen.Translation.route,
"main_dictionary",
"main_vocabulary",
"main_exercise",
@@ -121,10 +122,11 @@ fun AppNavHost(
}
) {
composable(Screen.Home.route) {
- TranslationScreen(navController = navController)
+ HomeScreen(navController = navController)
}
// Define all other navigation graphs at the same top level.
+ homeGraph(navController)
translationGraph(navController)
dictionaryGraph(navController)
vocabularyGraph(navController)
@@ -132,11 +134,23 @@ fun AppNavHost(
settingsGraph(navController)
}
}
+
+fun NavGraphBuilder.homeGraph(navController: NavHostController) {
+ navigation(
+ startDestination = "main_home",
+ route = Screen.Home.route
+ ) {
+ composable("main_home") {
+ HomeScreen(navController = navController)
+ }
+ }
+}
+
@OptIn(androidx.compose.animation.ExperimentalAnimationApi::class)
fun NavGraphBuilder.translationGraph(navController: NavHostController) {
navigation(
startDestination = "main_translation",
- route = Screen.Home.route
+ route = Screen.Translation.route
) {
composable("main_translation") {
TranslationScreen(navController = navController)
diff --git a/app/src/main/java/eu/gaudian/translator/view/composable/BottomNavigationBar.kt b/app/src/main/java/eu/gaudian/translator/view/composable/BottomNavigationBar.kt
index 373271f..31466f6 100644
--- a/app/src/main/java/eu/gaudian/translator/view/composable/BottomNavigationBar.kt
+++ b/app/src/main/java/eu/gaudian/translator/view/composable/BottomNavigationBar.kt
@@ -48,7 +48,8 @@ sealed class Screen(
val selectedIcon: ImageVector,
val unselectedIcon: ImageVector
) {
- object Home : Screen("home", R.string.label_translation, AppIcons.TranslateFilled, AppIcons.TranslateOutlined)
+ object Home : Screen("home", R.string.label_home, AppIcons.Home, AppIcons.Home)
+ object Translation : Screen("translation", R.string.label_translation, AppIcons.TranslateFilled, AppIcons.TranslateOutlined)
object Dictionary : Screen("dictionary", R.string.label_dictionary, AppIcons.DictionaryFilled, AppIcons.DictionaryOutlined)
object Exercises : Screen("exercises", R.string.label_exercises, AppIcons.DictionaryFilled, AppIcons.DictionaryOutlined)
object Vocabulary : Screen("vocabulary", R.string.label_vocabulary, AppIcons.VocabularyFilled, AppIcons.VocabularyOutlined)
@@ -56,9 +57,9 @@ sealed class Screen(
companion object {
fun getAllScreens(showExperimental: Boolean = false): List {
- val screens = mutableListOf(Home, Dictionary, Vocabulary, Settings)
+ val screens = mutableListOf(Home, Translation, Dictionary, Vocabulary, Settings)
if (showExperimental) {
- screens.add(2, Exercises)
+ screens.add(3, Exercises)
}
return screens
}
diff --git a/app/src/main/java/eu/gaudian/translator/view/home/HomeScreen.kt b/app/src/main/java/eu/gaudian/translator/view/home/HomeScreen.kt
new file mode 100644
index 0000000..c38a8fc
--- /dev/null
+++ b/app/src/main/java/eu/gaudian/translator/view/home/HomeScreen.kt
@@ -0,0 +1,359 @@
+package eu.gaudian.translator.view.home
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+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.AddCircle
+import androidx.compose.material.icons.filled.CheckCircle
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material.icons.filled.LocalFireDepartment
+import androidx.compose.material.icons.filled.Notifications
+import androidx.compose.material.icons.filled.Person
+import androidx.compose.material.icons.filled.Psychology
+import androidx.compose.material.icons.filled.TrendingUp
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+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.navigation.NavHostController
+
+@Composable
+fun HomeScreen(
+ navController: NavHostController,
+ modifier: Modifier = Modifier
+) {
+ // A Box with TopCenter alignment keeps the UI centered on wide screens (tablets/foldables)
+ Box(
+ modifier = modifier.fillMaxSize(),
+ contentAlignment = Alignment.TopCenter
+ ) {
+ LazyColumn(
+ modifier = Modifier
+ .widthIn(max = 700.dp) // Prevents extreme stretching on tablets
+ .fillMaxSize()
+ .padding(horizontal = 20.dp, vertical = 24.dp),
+ verticalArrangement = Arrangement.spacedBy(20.dp)
+ ) {
+ item { TopProfileSection() }
+ item { StreakAndGoalSection() }
+ item {
+ ActionCard(
+ title = "Daily Review",
+ subtitle = "42 words need attention",
+ icon = Icons.Default.Psychology,
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary
+ )
+ }
+ item {
+ ActionCard(
+ title = "New Words",
+ subtitle = "Expand your vocabulary",
+ icon = Icons.Default.AddCircle,
+ containerColor = MaterialTheme.colorScheme.surfaceVariant,
+ contentColor = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ item { WeeklyProgressSection() }
+ item { BottomStatsSection() }
+
+ // Bottom padding for edge-to-edge screens
+ item { Spacer(modifier = Modifier.height(24.dp)) }
+ }
+ }
+}
+
+@Composable
+fun TopProfileSection() {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ // Dummy Avatar
+ Box(
+ modifier = Modifier
+ .size(56.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceVariant),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(Icons.Default.Person, contentDescription = "Profile", tint = MaterialTheme.colorScheme.onSurfaceVariant)
+ }
+
+ Spacer(modifier = Modifier.width(16.dp))
+
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = "Welcome back,",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
+ )
+ Text(
+ text = "Alex Rivera 👋",
+ style = MaterialTheme.typography.titleLarge,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ }
+
+ IconButton(
+ onClick = { /* TODO: Open notifications */ },
+ modifier = Modifier
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Notifications,
+ contentDescription = "Notifications",
+ tint = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+}
+
+@Composable
+fun StreakAndGoalSection() {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ // Streak Card
+ StatCard(
+ modifier = Modifier.weight(1f),
+ icon = Icons.Default.LocalFireDepartment,
+ title = "7 Days",
+ subtitle = "CURRENT STREAK"
+ )
+ // Goal Card
+ GoalCard(
+ modifier = Modifier.weight(1f),
+ progress = 0.7f,
+ title = "14 / 20",
+ subtitle = "DAILY GOAL"
+ )
+ }
+}
+
+@Composable
+fun StatCard(
+ modifier: Modifier = Modifier,
+ icon: ImageVector,
+ title: String,
+ subtitle: String
+) {
+ Card(
+ modifier = modifier,
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Column(
+ modifier = Modifier.padding(20.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.size(32.dp)
+ )
+ Spacer(modifier = Modifier.height(12.dp))
+ Text(text = title, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
+ Spacer(modifier = Modifier.height(4.dp))
+ Text(text = subtitle, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f))
+ }
+ }
+}
+
+@Composable
+fun GoalCard(
+ modifier: Modifier = Modifier,
+ progress: Float,
+ title: String,
+ subtitle: String
+) {
+ Card(
+ modifier = modifier,
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Column(
+ modifier = Modifier.padding(20.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Box(contentAlignment = Alignment.Center) {
+ CircularProgressIndicator(
+ progress = { progress },
+ modifier = Modifier.size(48.dp),
+ strokeWidth = 4.dp,
+ color = MaterialTheme.colorScheme.primary,
+ trackColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)
+ )
+ Text(text = "${(progress * 100).toInt()}%", style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Bold)
+ }
+ Spacer(modifier = Modifier.height(12.dp))
+ Text(text = title, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
+ Spacer(modifier = Modifier.height(4.dp))
+ Text(text = subtitle, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f))
+ }
+ }
+}
+
+@Composable
+fun ActionCard(
+ title: String,
+ subtitle: String,
+ icon: ImageVector,
+ containerColor: Color,
+ contentColor: Color
+) {
+ Card(
+ modifier = Modifier.fillMaxWidth(),
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = containerColor, contentColor = contentColor)
+ ) {
+ Row(
+ modifier = Modifier.padding(20.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null,
+ modifier = Modifier.size(40.dp)
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(text = title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
+ Text(text = subtitle, style = MaterialTheme.typography.bodyMedium, color = contentColor.copy(alpha = 0.8f))
+ }
+ Icon(
+ imageVector = Icons.Default.ChevronRight,
+ contentDescription = "Go",
+ modifier = Modifier.size(24.dp)
+ )
+ }
+ }
+}
+
+@Composable
+fun WeeklyProgressSection() {
+ Column {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(text = "Weekly Progress", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
+ TextButton(onClick = { /* TODO */ }) {
+ Text("See History")
+ }
+ }
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(200.dp), // Fixed height for dummy chart area
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp),
+ verticalArrangement = Arrangement.Bottom
+ ) {
+ // Dummy Chart Graph Space
+ Spacer(modifier = Modifier.weight(1f))
+
+ // Days row
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun").forEach { day ->
+ Text(
+ text = day,
+ style = MaterialTheme.typography.labelSmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
+ )
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun BottomStatsSection() {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ // Total Words
+ Card(
+ modifier = Modifier.weight(1f),
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Column(modifier = Modifier.padding(20.dp)) {
+ Text(text = "TOTAL WORDS", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f))
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(text = "1,284", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
+ Spacer(modifier = Modifier.height(8.dp))
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Icon(Icons.Default.TrendingUp, contentDescription = null, tint = Color.Green, modifier = Modifier.size(16.dp))
+ Spacer(modifier = Modifier.width(4.dp))
+ Text(text = "+12 today", style = MaterialTheme.typography.labelSmall, color = Color.Green)
+ }
+ }
+ }
+
+ // Accuracy
+ Card(
+ modifier = Modifier.weight(1f),
+ shape = RoundedCornerShape(20.dp),
+ colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant)
+ ) {
+ Column(modifier = Modifier.padding(20.dp)) {
+ Text(text = "ACCURACY", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f))
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(text = "92%", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
+ Spacer(modifier = Modifier.height(8.dp))
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Icon(Icons.Default.CheckCircle, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(16.dp))
+ Spacer(modifier = Modifier.width(4.dp))
+ Text(text = "Master level", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.primary)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 999655a..524af30 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -288,6 +288,7 @@
Hard
First Row is a Header
Hide examples
+ Home
Import
Import Table (CSV)
In Stages