Fix stats render and add 'disabled-member' setting
This commit is contained in:
@@ -31,6 +31,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Archive
|
||||
import androidx.compose.material.icons.filled.Brightness2
|
||||
import androidx.compose.material.icons.filled.Group
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.Palette
|
||||
import androidx.compose.material.icons.filled.Sync
|
||||
@@ -84,6 +85,7 @@ fun SettingsScreen(
|
||||
val keyOfflineMode = stringResource(R.string.pref_key_offline_mode)
|
||||
val keyShowArchived = stringResource(R.string.pref_key_show_archived)
|
||||
val keyBetaFeatures = stringResource(R.string.pref_key_beta_features)
|
||||
val keyStatsIncludeDeactivated = stringResource(R.string.pref_key_stats_include_deactivated)
|
||||
val keyAutoSyncOnOpen = stringResource(R.string.pref_key_auto_sync_on_open)
|
||||
val keyFillNewBillFromLast = stringResource(R.string.pref_key_fill_new_bill_from_last)
|
||||
val keyLastAccountSync = stringResource(R.string.pref_key_last_account_sync_timestamp)
|
||||
@@ -132,6 +134,9 @@ fun SettingsScreen(
|
||||
var fillNewBillFromLast by remember(keyFillNewBillFromLast) {
|
||||
mutableStateOf(sharedPreferences.getBoolean(keyFillNewBillFromLast, false))
|
||||
}
|
||||
var statsIncludeDeactivated by remember(keyStatsIncludeDeactivated) {
|
||||
mutableStateOf(sharedPreferences.getBoolean(keyStatsIncludeDeactivated, false))
|
||||
}
|
||||
|
||||
val syncIntervals = SyncSettings.INTERVAL_CHOICES_MINUTES
|
||||
val syncIntervalLabels = listOf(
|
||||
@@ -304,6 +309,18 @@ fun SettingsScreen(
|
||||
}
|
||||
)
|
||||
|
||||
SettingsSwitchPreference(
|
||||
title = stringResource(R.string.settings_stats_include_deactivated),
|
||||
icon = Icons.Default.Group,
|
||||
checked = statsIncludeDeactivated,
|
||||
onCheckedChange = {
|
||||
statsIncludeDeactivated = it
|
||||
sharedPreferences.edit {
|
||||
putBoolean(keyStatsIncludeDeactivated, it)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
SettingsSliderPreference(
|
||||
title = stringResource(R.string.settings_auto_sync_on_open),
|
||||
summary = stringResource(R.string.settings_auto_sync_on_open_summary),
|
||||
|
||||
@@ -121,17 +121,19 @@ fun ProjectSankeyDiagram(
|
||||
val catMap = mutableMapOf<Long, Double>()
|
||||
|
||||
activeBills.forEach { bill ->
|
||||
val totalWeight = bill.billOwers.sumOf { membersMap[it.memberId]?.weight ?: 1.0 }
|
||||
val totalWeight = bill.billOwers.sumOf { membersMap[it.memberId]?.weight ?: 0.0 }
|
||||
if (totalWeight > 0) {
|
||||
if (selectedMemberId == -1L) {
|
||||
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + bill.amount
|
||||
bill.billOwers.forEach { bo ->
|
||||
val weight = membersMap[bo.memberId]?.weight ?: 1.0
|
||||
if (membersMap.containsKey(bo.memberId)) {
|
||||
val weight = membersMap[bo.memberId]?.weight ?: 0.0
|
||||
spentMap[bo.memberId] = (spentMap[bo.memberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bill.billOwers.find { it.memberId == selectedMemberId }?.let { bo ->
|
||||
val weight = membersMap[bo.memberId]?.weight ?: 1.0
|
||||
val weight = membersMap[bo.memberId]?.weight ?: 0.0
|
||||
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||
spentMap[selectedMemberId] = (spentMap[selectedMemberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||
}
|
||||
@@ -344,7 +346,9 @@ private fun SankeyContent(
|
||||
scope.launch { topFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
||||
} else Modifier), contentAlignment = Alignment.Center) {
|
||||
Column(modifier = Modifier.fillMaxSize().background(color = member?.let { Color(it.r ?: 128, it.g ?: 128, it.b ?: 128) } ?: Color.Gray, shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||
if (wDp >= 32.dp) {
|
||||
Text(text = member?.name ?: "???", color = Color.White, fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
||||
}
|
||||
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
||||
}
|
||||
}
|
||||
@@ -382,7 +386,9 @@ private fun SankeyContent(
|
||||
scope.launch { bottomFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
||||
} else Modifier), contentAlignment = Alignment.Center) {
|
||||
Column(modifier = Modifier.fillMaxSize().background(color = category?.color?.let { try { Color(it.toColorInt()) } catch (_: Exception) { Color(0xFF999999) } } ?: Color(0xFF999999), shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||
if (wDp >= 24.dp) {
|
||||
Text(text = category?.icon ?: "❔", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
||||
}
|
||||
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ fun ProjectStatisticsScreen(
|
||||
"Sankey"
|
||||
)
|
||||
|
||||
val keyStatsIncludeDeactivated = stringResource(R.string.pref_key_stats_include_deactivated)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -103,7 +105,11 @@ fun ProjectStatisticsScreen(
|
||||
val bills = db.getBillsOfProject(proj.id)
|
||||
val categories = db.getCategories(proj.id)
|
||||
val paymentModes = db.getPaymentModes(proj.id)
|
||||
StatisticsData(members, bills, categories, paymentModes)
|
||||
|
||||
val includeDeactivated = prefs.getBoolean(keyStatsIncludeDeactivated, false)
|
||||
val filteredMembers = if (includeDeactivated) members else members.filter { it.isActivated }
|
||||
|
||||
StatisticsData(filteredMembers, bills, categories, paymentModes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||
<string name="settings_stats_include_deactivated">Include deactivated members in stats</string>
|
||||
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||
<string name="pref_value_sync_1m">1 minute</string>
|
||||
@@ -170,6 +171,7 @@
|
||||
<string name="pref_key_offline_mode" translatable="false">offlineMode</string>
|
||||
<string name="pref_key_show_archived" translatable="false">showArchived</string>
|
||||
<string name="pref_key_beta_features" translatable="false">betaFeatures</string>
|
||||
<string name="pref_key_stats_include_deactivated" translatable="false">statsIncludeDeactivated</string>
|
||||
<string name="pref_key_auto_sync_on_open" translatable="false">autoSyncOnOpen</string>
|
||||
<string name="pref_key_last_account_sync_timestamp" translatable="false">lastAccountSyncTimestamp</string>
|
||||
<string name="pref_key_fill_new_bill_from_last" translatable="false">fillNewBillFromLast</string>
|
||||
|
||||
Reference in New Issue
Block a user