Merge remote-tracking branch 'origin/main' into Florian

# Conflicts:
#	Ledger/app/src/main/java/at/xaxa/ledger/ui/LedgerUI.kt
This commit is contained in:
Florian 2025-01-15 18:35:19 +01:00
commit ae1759e149
7 changed files with 117 additions and 59 deletions

View File

@ -12,7 +12,8 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument import androidx.navigation.navArgument
import at.xaxa.ledger.ui.add.Add import at.xaxa.ledger.ui.add.Add
import at.xaxa.ledger.ui.category.add.addCategory import at.xaxa.ledger.ui.category.CategoryOverview
import at.xaxa.ledger.ui.category.add.AddCategory
import at.xaxa.ledger.ui.category.edit.EditCategory import at.xaxa.ledger.ui.category.edit.EditCategory
import at.xaxa.ledger.ui.edit.Edit import at.xaxa.ledger.ui.edit.Edit
import at.xaxa.ledger.ui.home.Home import at.xaxa.ledger.ui.home.Home
@ -22,6 +23,7 @@ enum class AppRoutes(val route: String) {
Add("add"), Add("add"),
Edit("edit/{entryId}"), Edit("edit/{entryId}"),
Category("category"), Category("category"),
AddCategory("category/add"),
EditCategory("categoryEdit/{categoryId}") EditCategory("categoryEdit/{categoryId}")
} }
@ -84,10 +86,17 @@ fun LedgerApp(modifier: Modifier = Modifier){
} }
) )
} }
composable(AppRoutes.Category.route){ composable(AppRoutes.AddCategory.route){
addCategory( AddCategory(
onButtonClick = { onButtonClick = {
navController.navigate("home") navController.navigate("gome")
}
)
}
composable(AppRoutes.Category.route){
CategoryOverview(
onButtonClick = {
navController.navigate("category/add")
}, },
onCardClick = { onCardClick = {
navController.navigate("categoryEdit/$it") navController.navigate("categoryEdit/$it")

View File

@ -13,14 +13,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.DateRange
import androidx.compose.material.icons.rounded.ShoppingCart import androidx.compose.material.icons.filled.List
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DatePicker import androidx.compose.material3.DatePicker
@ -58,7 +57,7 @@ import java.util.Locale
// region Header Card // region Header Card
@Composable @Composable
fun HeaderCard(modifier: Modifier = Modifier, balance: String) { fun HeaderCard(modifier: Modifier = Modifier, balance: String, onCategoryButton: () -> Unit) {
Surface( Surface(
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
color = Color(0xfff9f9f9), color = Color(0xfff9f9f9),
@ -75,6 +74,17 @@ fun HeaderCard(modifier: Modifier = Modifier, balance: String) {
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) { ) {
Column() {
IconButton(onClick = {
onCategoryButton()
}) {
Icon(
imageVector = Icons.Filled.List,
contentDescription = "Add to list", // Provide a meaningful description for accessibility
tint = MaterialTheme.colorScheme.onSurface // Optional: Adjust the tint as needed
)
}
}
LayoutMediaTextHeader(modifier, balance) LayoutMediaTextHeader(modifier, balance)
} }
} }
@ -119,7 +129,7 @@ fun LayoutMediaTextHeader(modifier: Modifier = Modifier, balance: String) {
@Preview() @Preview()
@Composable @Composable
private fun HeaderCardPreview() { private fun HeaderCardPreview() {
HeaderCard(Modifier, "-4500627.98€") HeaderCard(Modifier, "-4500627.98€", {})
} }
// endregion // endregion
@ -148,7 +158,7 @@ fun HorizontalCard(modifier: Modifier = Modifier, name: String, date: String, am
fun CategoryCard( fun CategoryCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
name: String, name: String,
iconid: Int, iconId: Int,
onClick: () -> Unit onClick: () -> Unit
) { ) {
Surface( Surface(
@ -166,14 +176,7 @@ fun CategoryCard(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
LayoutMediaText(modifier, name) LayoutMediaText(modifier, name, iconId)
Icon(
imageVector = icons[iconid],
contentDescription = "$name Icon",
modifier = Modifier.size(24.dp),
tint = Color.Black
)
} }
} }
} }
@ -227,17 +230,20 @@ fun LayoutMediaText(modifier: Modifier = Modifier, name: String, date: String, a
} }
} }
@Composable @Composable
fun LayoutMediaText(modifier: Modifier = Modifier, name: String) { fun LayoutMediaText(modifier: Modifier = Modifier, name: String, iconId: Int) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column( Row(
verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Top), verticalAlignment = Alignment.CenterVertically, // Aligns items vertically in the center
modifier = Modifier horizontalArrangement = Arrangement.spacedBy(4.dp) // Adds space between the icon and text
.weight(1f)
) { ) {
Icon(
icons[iconId],
contentDescription = "$name Icon"
)
Text( Text(
text = name, text = name,
color = Color(0xff1b1b1b), color = Color(0xff1b1b1b),
@ -248,7 +254,6 @@ fun LayoutMediaText(modifier: Modifier = Modifier, name: String) {
letterSpacing = 0.15.sp letterSpacing = 0.15.sp
) )
) )
} }
} }
} }

View File

@ -0,0 +1,63 @@
package at.xaxa.ledger.ui.category
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import at.xaxa.ledger.ui.AppViewModelProvider
import at.xaxa.ledger.ui.ButtonSuccess
import at.xaxa.ledger.ui.CategoryCard
@Composable
fun CategoryOverview(
onButtonClick: () -> Unit,
modifier: Modifier = Modifier,
onCardClick: (Int) -> Unit,
categoryViewModel: CategoryViewModel = viewModel(factory = AppViewModelProvider.Factory)
){
val categories by categoryViewModel.categoryUiState.categories.collectAsState(initial = emptyList())
Column(
modifier = modifier
.fillMaxSize()
.padding(16.dp, 0.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
LazyColumn(
Modifier.weight(1f)
) {
items(categories) { item ->
Column(
modifier = Modifier.padding(vertical = 4.dp)
) {
CategoryCard(
modifier = modifier,
name = item.categoryName,
iconId = item.icon,
onClick = { onCardClick(item._id) }
)
}
}
}
// Sticky footer content
Box(
modifier = Modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
ButtonSuccess(modifier = Modifier, "Add Category", onClick = { onButtonClick() })
}
}
}

View File

@ -3,6 +3,7 @@ package at.xaxa.ledger.ui.category.add
import android.util.Log import android.util.Log
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.defaultMinSize
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.padding import androidx.compose.foundation.layout.padding
@ -16,6 +17,7 @@ import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.LocationOn
@ -28,6 +30,7 @@ import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -43,7 +46,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import at.xaxa.ledger.data.db.Category.CategoryEntity import at.xaxa.ledger.data.db.Category.CategoryEntity
import at.xaxa.ledger.ui.AppViewModelProvider import at.xaxa.ledger.ui.AppViewModelProvider
import at.xaxa.ledger.ui.ButtonSuccess import at.xaxa.ledger.ui.ButtonSuccess
import at.xaxa.ledger.ui.CategoryCard
import at.xaxa.ledger.ui.category.CategoryViewModel import at.xaxa.ledger.ui.category.CategoryViewModel
import at.xaxa.ledger.ui.category.iconNames import at.xaxa.ledger.ui.category.iconNames
import at.xaxa.ledger.ui.category.icons import at.xaxa.ledger.ui.category.icons
@ -51,10 +53,9 @@ import at.xaxa.ledger.ui.category.icons
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun addCategory( fun AddCategory(
onButtonClick: () -> Unit, onButtonClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onCardClick: (Int) -> Unit,
categoryViewModel: CategoryViewModel = viewModel(factory = AppViewModelProvider.Factory) categoryViewModel: CategoryViewModel = viewModel(factory = AppViewModelProvider.Factory)
) { ) {
@ -62,7 +63,10 @@ fun addCategory(
var selectedIconIndex by remember { mutableStateOf(0) } // Store index of selected icon var selectedIconIndex by remember { mutableStateOf(0) } // Store index of selected icon
var expanded by remember { mutableStateOf(false) } // Controls dropdown visibility var expanded by remember { mutableStateOf(false) } // Controls dropdown visibility
/*
val categories by categoryViewModel.categoryUiState.categories.collectAsState(initial = emptyList()) val categories by categoryViewModel.categoryUiState.categories.collectAsState(initial = emptyList())
val category = categoryViewModel.categoryUi.category
var expanded by remember { mutableStateOf(false) }*/
Column( Column(
modifier = modifier modifier = modifier
@ -87,6 +91,12 @@ fun addCategory(
onValueChange = {}, onValueChange = {},
label = { Text("Icon") }, label = { Text("Icon") },
readOnly = true, readOnly = true,
leadingIcon = {
Icon(
imageVector = icons[selectedIconIndex], // Replace with your desired icon
contentDescription = "Leading Icon"
)
},
trailingIcon = { trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
}, },
@ -132,28 +142,12 @@ fun addCategory(
categoryName = name, categoryName = name,
icon = selectedIconIndex // Save selected index as the icon ID icon = selectedIconIndex // Save selected index as the icon ID
) )
categoryViewModel.addCategory(newCategory) categoryViewModel.addCategory(newCategory)
onButtonClick() onButtonClick()
} }
} }
) )
} }
LazyColumn(
Modifier.weight(1f)
) {
items(categories) { item ->
Column(
modifier = Modifier.padding(vertical = 4.dp)
) {
CategoryCard(
modifier = modifier,
name = item.categoryName,
iconid = item.icon,
onClick = { onCardClick(item._id) }
)
}
}
}
} }
} }

View File

@ -28,7 +28,7 @@ import at.xaxa.ledger.ui.ButtonSuccess
import at.xaxa.ledger.ui.DatePickerDocked import at.xaxa.ledger.ui.DatePickerDocked
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun Edit(modifier: Modifier = Modifier, onCardClick: () -> Unit, editViewModel : EditViewModel = viewModel(factory = AppViewModelProvider.Factory), onValueChange: (Entry) -> Unit = {}, fun Edit(modifier: Modifier = Modifier, onCardClick: () -> Unit, editViewModel : EditViewModel = viewModel(factory = AppViewModelProvider.Factory), onValueChange: (Entry) -> Unit = {},
) { ) {
val entry = editViewModel.editUiState.entry val entry = editViewModel.editUiState.entry

View File

@ -44,6 +44,7 @@ class EditViewModel(private val savedStateHandle: SavedStateHandle,
} }
editUiState = EditUI(entry) editUiState = EditUI(entry)
getAllCategories()
findCategoryByID(entry.categoryID) findCategoryByID(entry.categoryID)
} }
} }

View File

@ -39,21 +39,7 @@ fun Home(modifier: Modifier = Modifier, onCardClick: (Int) -> Unit, onButtonClic
.weight(1f) .weight(1f)
) { ) {
stickyHeader { stickyHeader {
HeaderCard(modifier = modifier, "-13563.00€") HeaderCard(modifier = modifier, "-13563.00€", onCatButtonClick)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp), // Add slight padding from the header
contentAlignment = Alignment.TopStart // Align button to the top-left
) {
ButtonSuccess(
modifier = Modifier
.width(120.dp) // Make the button smaller
.padding(4.dp), // Add some padding for better touch area
text = "Add Category",
onClick = { onCatButtonClick() }
)
}
} }
items(state) { item -> items(state) { item ->
Column( Column(