refactor MainActivity to use hiltViewModel and relocate AppScaffold to its own file

This commit is contained in:
jonasgaudian
2026-02-13 15:57:15 +01:00
parent 391fe403ad
commit b5a9f5873a
4 changed files with 106 additions and 49 deletions

1
.idea/misc.xml generated
View File

@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<list size="1"> <list size="1">

View File

@@ -6,7 +6,6 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
@@ -45,6 +44,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavDestination.Companion.hierarchy
@@ -58,6 +58,7 @@ import eu.gaudian.translator.ui.theme.AllFonts
import eu.gaudian.translator.ui.theme.AllThemes import eu.gaudian.translator.ui.theme.AllThemes
import eu.gaudian.translator.ui.theme.buildColorScheme import eu.gaudian.translator.ui.theme.buildColorScheme
import eu.gaudian.translator.utils.Log import eu.gaudian.translator.utils.Log
import eu.gaudian.translator.utils.findActivity
import eu.gaudian.translator.view.composable.AppAlertDialog import eu.gaudian.translator.view.composable.AppAlertDialog
import eu.gaudian.translator.view.composable.BottomNavigationBar import eu.gaudian.translator.view.composable.BottomNavigationBar
import eu.gaudian.translator.view.composable.Screen import eu.gaudian.translator.view.composable.Screen
@@ -76,7 +77,7 @@ val LocalConnectionConfigured = compositionLocalOf { true }
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val statusViewModel: StatusViewModel by viewModels()
private val settingsViewModel: SettingsViewModel by viewModels() private val settingsViewModel: SettingsViewModel by viewModels()
private var isReady = false private var isReady = false
private var isUiLoaded = false private var isUiLoaded = false
@@ -100,10 +101,7 @@ class MainActivity : ComponentActivity() {
// Show UI immediately and load data in background // Show UI immediately and load data in background
setContent { setContent {
AppTheme(settingsViewModel = settingsViewModel) { AppTheme(settingsViewModel = settingsViewModel) {
TranslatorApp( TranslatorApp(settingsViewModel = settingsViewModel)
statusViewModel = statusViewModel,
settingsViewModel = settingsViewModel
)
} }
} }
@@ -146,9 +144,15 @@ class MainActivity : ComponentActivity() {
@SuppressLint("LocalContextResourcesRead") @SuppressLint("LocalContextResourcesRead")
@Composable @Composable
fun TranslatorApp( fun TranslatorApp(
statusViewModel: StatusViewModel,
settingsViewModel: SettingsViewModel settingsViewModel: SettingsViewModel
) { ) {
val activity = LocalContext.current.findActivity()
val statusViewModel: StatusViewModel = hiltViewModel(activity)
val navController = rememberNavController() val navController = rememberNavController()
val statusState by statusViewModel.status.collectAsStateWithLifecycle() val statusState by statusViewModel.status.collectAsStateWithLifecycle()
val keyboardInsets = WindowInsets.ime val keyboardInsets = WindowInsets.ime
@@ -171,7 +175,6 @@ fun TranslatorApp(
showExitDialog = true showExitDialog = true
} }
val activity = LocalActivity.current
if (showExitDialog) { if (showExitDialog) {
AppAlertDialog( AppAlertDialog(
@@ -182,7 +185,7 @@ fun TranslatorApp(
TextButton(onClick = { TextButton(onClick = {
showExitDialog = false showExitDialog = false
// Minimize the app similar to default back at root behavior // Minimize the app similar to default back at root behavior
activity?.moveTaskToBack(true) activity.moveTaskToBack(true)
}) { }) {
Text(stringResource(R.string.quit)) Text(stringResource(R.string.quit))
} }

View File

@@ -0,0 +1,94 @@
package eu.gaudian.translator.view.composable
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.FabPosition
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import eu.gaudian.translator.R
@Composable
fun AppScaffold(
modifier: Modifier = Modifier,
topBar: @Composable () -> Unit = {},
snackbarHost: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
containerColor: Color = MaterialTheme.colorScheme.background,
contentColor: Color = contentColorFor(containerColor),
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
content: @Composable (PaddingValues) -> Unit
) {
// A Scaffold variant that enforces no bottom bar while keeping proper content padding handling.
Scaffold(
modifier = modifier,
topBar = topBar,
snackbarHost = snackbarHost,
containerColor = containerColor,
contentColor = contentColor,
bottomBar = {},
floatingActionButton = floatingActionButton,
floatingActionButtonPosition = floatingActionButtonPosition
) { innerPadding ->
// Ensure bottom padding is always 0.dp
val customPadding = PaddingValues(
top = innerPadding.calculateTopPadding(),
bottom = 0.dp, // Force bottom padding to 0.dp
start = innerPadding.calculateLeftPadding(androidx.compose.ui.unit.LayoutDirection.Ltr),
end = innerPadding.calculateRightPadding(androidx.compose.ui.unit.LayoutDirection.Ltr)
)
content(customPadding)
}
}
@Composable
fun ParrotTopBar() {
val navyBlue = Color(0xFF1A237E) // The color from your mockup
CenterAlignedTopAppBar(
title = {
Text(
text = "ParrotPal",
style = MaterialTheme.typography.titleLarge,
color = Color.White
)
},
navigationIcon = {
// Your new parrot logo icon
Icon(
painter = painterResource(id = R.drawable.ic_level_parrot),
contentDescription = "Logo",
modifier = Modifier.size(32.dp),
tint = Color.Unspecified // Keeps the logo's original colors
)
},
actions = {
IconButton(onClick = { /* Search */ }) {
Icon(Icons.Default.Search, contentDescription = "Search", tint = Color.White)
}
IconButton(onClick = { /* Profile */ }) {
Icon(Icons.Default.AccountCircle, contentDescription = "Profile", tint = Color.White)
}
},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = navyBlue
)
)
}

View File

@@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -28,19 +27,15 @@ import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.FabPosition
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -755,37 +750,3 @@ fun WrongOutlinedButton(
} }
} }
@Composable
fun AppScaffold(
modifier: Modifier = Modifier,
topBar: @Composable () -> Unit = {},
snackbarHost: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
containerColor: Color = MaterialTheme.colorScheme.background,
contentColor: Color = contentColorFor(containerColor),
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
content: @Composable (PaddingValues) -> Unit
) {
// A Scaffold variant that enforces no bottom bar while keeping proper content padding handling.
Scaffold(
modifier = modifier,
topBar = topBar,
snackbarHost = snackbarHost,
containerColor = containerColor,
contentColor = contentColor,
bottomBar = {},
floatingActionButton = floatingActionButton,
floatingActionButtonPosition = floatingActionButtonPosition
) { innerPadding ->
// Ensure bottom padding is always 0.dp
val customPadding = PaddingValues(
top = innerPadding.calculateTopPadding(),
bottom = 0.dp, // Force bottom padding to 0.dp
start = innerPadding.calculateLeftPadding(androidx.compose.ui.unit.LayoutDirection.Ltr),
end = innerPadding.calculateRightPadding(androidx.compose.ui.unit.LayoutDirection.Ltr)
)
content(customPadding)
}
}