fix: scroll to date when clicked on stats screen

This commit is contained in:
Rafal Wisniewski
2026-05-04 15:44:32 +02:00
parent 5fb54bf18e
commit aad0de1499
3 changed files with 52 additions and 22 deletions

View File

@@ -12,7 +12,6 @@ import androidx.compose.material3.DrawerValue
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -26,6 +25,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import cc.n0th1ng.tripmoney.data.entity.Category import cc.n0th1ng.tripmoney.data.entity.Category
import cc.n0th1ng.tripmoney.data.entity.Trip import cc.n0th1ng.tripmoney.data.entity.Trip
import cc.n0th1ng.tripmoney.navigation.BottomNavigation import cc.n0th1ng.tripmoney.navigation.BottomNavigation
@@ -111,17 +111,20 @@ fun NavigationDrawer() {
startDestination = if (currentTripId == -1) Screens.TRIP_PICKER else Screens.LIST_EXPENSE, startDestination = if (currentTripId == -1) Screens.TRIP_PICKER else Screens.LIST_EXPENSE,
modifier = Modifier.padding(innerPadding) modifier = Modifier.padding(innerPadding)
) { ) {
composable(Screens.LIST_EXPENSE) { composable(Screens.LIST_EXPENSE+"?dateToScroll={dateToScroll}",
arguments = listOf(navArgument("dateToScroll"){defaultValue = ""})) {
backStackEntry ->
ListExpenseScreen( ListExpenseScreen(
filter = filter, search = search, filter = filter, search = search,
initialAutoOpen = shouldTriggerAutoOpen, initialAutoOpen = shouldTriggerAutoOpen,
onAutoOpenConsumed = { hasHandledStartupOpen = true }) onAutoOpenConsumed = { hasHandledStartupOpen = true },
dateToScroll = backStackEntry.arguments?.getString("dateToScroll")?: "")
} }
composable(Screens.TRIP_PICKER) { composable(Screens.TRIP_PICKER) {
TripPickerScreen(navController) TripPickerScreen(navController)
} }
composable(Screens.STATISTICS) { composable(Screens.STATISTICS) {
StatisticsScreen() StatisticsScreen(navController)
} }
composable(Screens.SETTINGS) { composable(Screens.SETTINGS) {
SettingsScreen(navController) SettingsScreen(navController)

View File

@@ -90,7 +90,8 @@ fun ListExpenseScreen(
filter: Filter, filter: Filter,
search: String, search: String,
initialAutoOpen: Boolean, initialAutoOpen: Boolean,
onAutoOpenConsumed: () -> Unit onAutoOpenConsumed: () -> Unit,
dateToScroll: String
) { ) {
val settingsViewModel: SettingsViewModel = hiltViewModel() val settingsViewModel: SettingsViewModel = hiltViewModel()
val tripViewModel: TripViewModel = hiltViewModel() val tripViewModel: TripViewModel = hiltViewModel()
@@ -115,7 +116,8 @@ fun ListExpenseScreen(
isRecalculatingRate = isRecalculatingRate, isRecalculatingRate = isRecalculatingRate,
initialAutoOpen = initialAutoOpen, initialAutoOpen = initialAutoOpen,
onAutoOpenConsumed = onAutoOpenConsumed, onAutoOpenConsumed = onAutoOpenConsumed,
idToScroll = idToScroll idToScroll = idToScroll,
dateToScroll = dateToScroll
) )
} }
@@ -130,7 +132,8 @@ fun ListExpenseScreen(
isRecalculatingRate: Boolean, isRecalculatingRate: Boolean,
initialAutoOpen: Boolean, initialAutoOpen: Boolean,
onAutoOpenConsumed: () -> Unit, onAutoOpenConsumed: () -> Unit,
idToScroll: Int idToScroll: Int,
dateToScroll: String
) { ) {
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
@@ -181,6 +184,16 @@ fun ListExpenseScreen(
} }
} else { } else {
LaunchedEffect(Unit) {
if (dateToScroll == "") return@LaunchedEffect
for (index in 0 until items.itemCount) {
val item = items.peek(index)
if (item is ExpenseListItemUi.Header && item.date.toString() == dateToScroll) {
listState.animateScrollToItem(index)
break
}
}
}
LaunchedEffect(idToScroll) { LaunchedEffect(idToScroll) {
if (idToScroll == -1) return@LaunchedEffect if (idToScroll == -1) return@LaunchedEffect
for (index in 0 until items.itemCount) { for (index in 0 until items.itemCount) {
@@ -527,7 +540,8 @@ fun PreviewListExpenseScreen() {
isRecalculatingRate = true, isRecalculatingRate = true,
false, false,
{}, {},
0 0,
""
) )
} }
@@ -553,7 +567,8 @@ fun PreviewListExpenseScreenWithoutExpenses() {
isRecalculatingRate = true, isRecalculatingRate = true,
false, false,
{}, {},
0 0,
""
) )
} }
@@ -573,7 +588,8 @@ fun PreviewListExpenseScreenWithoutTrip() {
isRecalculatingRate = true, isRecalculatingRate = true,
false, false,
{}, {},
0 0,
""
) )
} }

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -42,10 +43,12 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavController
import cc.n0th1ng.tripmoney.data.dto.SummaryPerCategory import cc.n0th1ng.tripmoney.data.dto.SummaryPerCategory
import cc.n0th1ng.tripmoney.data.dto.SummaryPerDay import cc.n0th1ng.tripmoney.data.dto.SummaryPerDay
import cc.n0th1ng.tripmoney.data.entity.Category import cc.n0th1ng.tripmoney.data.entity.Category
import cc.n0th1ng.tripmoney.data.entity.Trip import cc.n0th1ng.tripmoney.data.entity.Trip
import cc.n0th1ng.tripmoney.navigation.Screens
import cc.n0th1ng.tripmoney.theme.TripMoneyTheme import cc.n0th1ng.tripmoney.theme.TripMoneyTheme
import cc.n0th1ng.tripmoney.utils.AllPreviews import cc.n0th1ng.tripmoney.utils.AllPreviews
import cc.n0th1ng.tripmoney.utils.Currencies import cc.n0th1ng.tripmoney.utils.Currencies
@@ -60,7 +63,7 @@ import java.time.format.DateTimeFormatter
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun StatisticsScreen() { fun StatisticsScreen(navController: NavController) {
val expenseAndCategoryViewModel: ExpenseAndCategoryViewModel = hiltViewModel() val expenseAndCategoryViewModel: ExpenseAndCategoryViewModel = hiltViewModel()
val settingsViewModel: SettingsViewModel = hiltViewModel() val settingsViewModel: SettingsViewModel = hiltViewModel()
val tripViewModel: TripViewModel = hiltViewModel() val tripViewModel: TripViewModel = hiltViewModel()
@@ -78,7 +81,10 @@ fun StatisticsScreen() {
summaryPerDayList, summaryPerDayList,
summaryAmount, summaryAmount,
Currencies.valueOf(currentTrip?.currency ?: Currencies.default().name), Currencies.valueOf(currentTrip?.currency ?: Currencies.default().name),
moneyLeft moneyLeft,
onDayClicked = {
date -> navController.navigate(Screens.LIST_EXPENSE + "?dateToScroll=$date")
}
) )
} }
@@ -89,7 +95,8 @@ fun StatisticsScreen(
summaryPerDayList: List<SummaryPerDay>, summaryPerDayList: List<SummaryPerDay>,
summaryAmount: Double, summaryAmount: Double,
tripCurrency: Currencies, tripCurrency: Currencies,
moneyLeft: Double? moneyLeft: Double?,
onDayClicked: (String) -> Unit
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@@ -117,7 +124,7 @@ fun StatisticsScreen(
modifier = Modifier.heightIn(max = 300.dp), modifier = Modifier.heightIn(max = 300.dp),
summaryPerCategoryList = summaryPerCategoryList summaryPerCategoryList = summaryPerCategoryList
) )
SummaryPerDayCard(modifier = Modifier.height(300.dp), summaryPerDayList = summaryPerDayList) SummaryPerDayCard(modifier = Modifier.height(300.dp), summaryPerDayList = summaryPerDayList, onDayClicked = onDayClicked)
} }
} }
@@ -217,7 +224,7 @@ fun SummaryPerCategoryCard(
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun SummaryPerDayCard(modifier: Modifier = Modifier, summaryPerDayList: List<SummaryPerDay>) { fun SummaryPerDayCard(modifier: Modifier = Modifier, summaryPerDayList: List<SummaryPerDay>, onDayClicked: (String) -> Unit) {
ElevatedCard( ElevatedCard(
modifier = modifier modifier = modifier
.fillMaxWidth(), .fillMaxWidth(),
@@ -246,9 +253,10 @@ fun SummaryPerDayCard(modifier: Modifier = Modifier, summaryPerDayList: List<Sum
.horizontalScroll(rememberScrollState()), .horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(5.dp) horizontalArrangement = Arrangement.spacedBy(5.dp)
) { ) {
summaryPerDayList.forEach { summaryPerDayList.forEach { it ->
DayCard( DayCard(
summaryPerDay = it summaryPerDay = it,
onDayClicked = {date -> onDayClicked(date)}
) )
} }
} }
@@ -316,7 +324,7 @@ fun CategoryCard(modifier: Modifier = Modifier, summaryPerCategory: SummaryPerCa
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
@Composable @Composable
fun DayCard(modifier: Modifier = Modifier, summaryPerDay: SummaryPerDay) { fun DayCard(modifier: Modifier = Modifier, summaryPerDay: SummaryPerDay, onDayClicked: (String) -> Unit) {
Column( Column(
modifier = modifier.fillMaxHeight(), verticalArrangement = Arrangement.Bottom, modifier = modifier.fillMaxHeight(), verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@@ -334,6 +342,7 @@ fun DayCard(modifier: Modifier = Modifier, summaryPerDay: SummaryPerDay) {
.fillMaxHeight(0.2f + (0.98f - 0.2f) * summaryPerDay.percent) .fillMaxHeight(0.2f + (0.98f - 0.2f) * summaryPerDay.percent)
.clip(RoundedCornerShape(width / 2)) .clip(RoundedCornerShape(width / 2))
.background(MaterialTheme.colorScheme.primary) .background(MaterialTheme.colorScheme.primary)
.clickable(onClick = {onDayClicked(summaryPerDay.day.toString())})
.padding(top = 5.dp) .padding(top = 5.dp)
) { ) {
Column( Column(
@@ -362,11 +371,11 @@ fun DayCard(modifier: Modifier = Modifier, summaryPerDay: SummaryPerDay) {
Text( Text(
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Light,
fontSize = (MaterialTheme.typography.labelSmall.fontSize.value - 2).sp, fontSize = (MaterialTheme.typography.labelSmall.fontSize.value - 2).sp,
lineHeight = 10.sp, lineHeight = 10.sp,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onTertiaryContainer, color = MaterialTheme.colorScheme.onTertiaryContainer,
text = summaryPerDay.day.format(DateTimeFormatter.ofPattern("E")) text = summaryPerDay.day.format(DateTimeFormatter.ofPattern("E"))
) )
} }
} }
@@ -387,7 +396,8 @@ fun PreviewStatisticScreen() {
summaryPerDayList, summaryPerDayList,
summaryAmount = 125.24, summaryAmount = 125.24,
Currencies.entries.random(), Currencies.entries.random(),
432.14 432.14,
{}
) )
} }
} }
@@ -405,7 +415,8 @@ fun PreviewStatisticScreenWithNoData() {
emptyList(), emptyList(),
summaryAmount = 0.0, summaryAmount = 0.0,
Currencies.entries.random(), Currencies.entries.random(),
null null,
{}
) )
} }
} }