1
0
mirror of https://github.com/oliexdev/openScale.git synced 2025-08-19 23:12:12 +02:00

Introduces a new "Chart Settings" screen accessible from the main settings menu.

This commit is contained in:
oliexdev
2025-08-15 15:56:56 +02:00
parent 365b1029c5
commit a3d18a1258
8 changed files with 121 additions and 5 deletions

View File

@@ -57,6 +57,9 @@ object UserPreferenceKeys {
val SAVED_BLUETOOTH_SCALE_ADDRESS = stringPreferencesKey("saved_bluetooth_scale_address")
val SAVED_BLUETOOTH_SCALE_NAME = stringPreferencesKey("saved_bluetooth_scale_name")
// Settings for chart
val SHOW_CHART_DATA_POINTS = booleanPreferencesKey("show_chart_data_points")
// Context strings for screen-specific settings (can be used as prefixes for dynamic keys)
const val OVERVIEW_SCREEN_CONTEXT = "overview_screen"
const val GRAPH_SCREEN_CONTEXT = "graph_screen"
@@ -90,6 +93,9 @@ interface UserSettingsRepository {
suspend fun saveBluetoothScale(address: String, name: String?)
suspend fun clearSavedBluetoothScale()
val showChartDataPoints: Flow<Boolean>
suspend fun setShowChartDataPoints(show: Boolean)
// Generic Settings Accessors
/**
* Observes a setting with the given key name and default value.
@@ -248,6 +254,19 @@ class UserSettingsRepositoryImpl(context: Context) : UserSettingsRepository {
}
}
override val showChartDataPoints: Flow<Boolean> = observeSetting(
UserPreferenceKeys.SHOW_CHART_DATA_POINTS.name,
true
).catch { exception ->
LogManager.e(TAG, "Error observing showChartDataPoints", exception)
emit(true)
}
override suspend fun setShowChartDataPoints(show: Boolean) {
LogManager.d(TAG, "Setting showChartDataPoints to: $show")
saveSetting(UserPreferenceKeys.SHOW_CHART_DATA_POINTS.name, show)
}
@Suppress("UNCHECKED_CAST")
override fun <T> observeSetting(keyName: String, defaultValue: T): Flow<T> {
LogManager.v(TAG, "Observing setting: key='$keyName', type='${defaultValue!!::class.simpleName}'")

View File

@@ -121,6 +121,7 @@ import com.health.openscale.ui.screen.overview.MeasurementDetailScreen
import com.health.openscale.ui.screen.overview.OverviewScreen
import com.health.openscale.ui.screen.settings.AboutScreen
import com.health.openscale.ui.screen.settings.BluetoothScreen
import com.health.openscale.ui.screen.settings.ChartSettingsScreen
import com.health.openscale.ui.screen.settings.DataManagementSettingsScreen
import com.health.openscale.ui.screen.settings.GeneralSettingsScreen
import com.health.openscale.ui.screen.settings.MeasurementTypeDetailScreen
@@ -683,6 +684,13 @@ fun AppNavigation(sharedViewModel: SharedViewModel) {
bluetoothViewModel = bluetoothViewModel
)
}
composable(Routes.CHART_SETTINGS) {
ChartSettingsScreen(
navController = navController,
sharedViewModel = sharedViewModel,
settingsViewModel = settingsViewModel
)
}
composable(Routes.DATA_MANAGEMENT_SETTINGS) {
DataManagementSettingsScreen(
navController = navController,

View File

@@ -46,6 +46,7 @@ object Routes {
const val MEASUREMENT_TYPES = "settings/types"
const val MEASUREMENT_TYPE_DETAIL = "settings/typeDetail"
const val BLUETOOTH_SETTINGS = "settings/bluetooth"
const val CHART_SETTINGS = "settings/chart"
const val DATA_MANAGEMENT_SETTINGS = "settings/dataManagement"
const val ABOUT_SETTINGS = "settings/about"

View File

@@ -63,6 +63,7 @@ import com.health.openscale.core.data.MeasurementTypeKey
import com.health.openscale.core.data.TimeRangeFilter
import com.health.openscale.core.database.UserPreferenceKeys
import com.health.openscale.core.database.UserSettingsRepository
import com.health.openscale.core.database.UserSettingsRepositoryImpl
import com.health.openscale.ui.screen.SharedViewModel
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisGuidelineComponent
@@ -142,6 +143,8 @@ fun LineChart(
val scope = rememberCoroutineScope()
val userSettingsRepository = sharedViewModel.userSettingRepository
val showDataPointsSetting by userSettingsRepository.showChartDataPoints.collectAsState(initial = true)
val uiSelectedTimeRange by rememberContextualTimeRangeFilter(
screenContextName = screenContextName,
userSettingsRepository = userSettingsRepository
@@ -503,7 +506,11 @@ fun LineChart(
LineCartesianLayer.LineProvider.series(
seriesEntriesForStartAxis.mapIndexedNotNull { index, _ ->
if (index < typeColorsForStartAxis.size) {
createLineSpec(typeColorsForStartAxis[index], statisticsMode = targetMeasurementTypeId != null)
createLineSpec(
color = typeColorsForStartAxis[index],
statisticsMode = targetMeasurementTypeId != null,
showPoints = showDataPointsSetting
)
} else null
}
)
@@ -522,7 +529,11 @@ fun LineChart(
LineCartesianLayer.LineProvider.series(
seriesEntriesForEndAxis.mapIndexedNotNull { index, _ ->
if (index < typeColorsForEndAxis.size) {
createLineSpec(typeColorsForEndAxis[index], statisticsMode = targetMeasurementTypeId != null)
createLineSpec(
color = typeColorsForEndAxis[index],
statisticsMode = targetMeasurementTypeId != null,
showPoints = showDataPointsSetting
)
} else null
}
)
@@ -702,9 +713,10 @@ private fun rememberXAxisValueFormatter(
* @param color The color of the line and points.
* @param statisticsMode If true, an area fill is added below the line, and points are hidden.
* This is typically used when `targetMeasurementTypeId` is set.
* @param showPoints If true, points are displayed on the line (unless in statisticsMode).
* @return A configured [LineCartesianLayer.Line].
*/
private fun createLineSpec(color: Color, statisticsMode : Boolean): LineCartesianLayer.Line {
private fun createLineSpec(color: Color, statisticsMode : Boolean, showPoints: Boolean): LineCartesianLayer.Line {
val lineStroke = LineCartesianLayer.LineStroke.Continuous(
thicknessDp = 2f,
)
@@ -719,10 +731,11 @@ private fun createLineSpec(color: Color, statisticsMode : Boolean): LineCartesia
// Area fill is shown in statistics mode (e.g., when a single type is focused)
areaFill = if (statisticsMode) LineCartesianLayer.AreaFill.single(Fill(color.copy(alpha = 0.2f).toArgb())) else null,
// Points on the line are shown unless in statistics mode
pointProvider = if (!statisticsMode) {
pointProvider = if (showPoints && !statisticsMode) {
LineCartesianLayer.PointProvider.single(
LineCartesianLayer.point(ShapeComponent(fill(color.copy(alpha = 0.7f)), CorneredShape.Pill), 6.dp)
) } else null,
)
} else null,
// dataLabel = null, // No data labels on points
pointConnector = LineCartesianLayer.PointConnector.cubic()
)

View File

@@ -0,0 +1,58 @@
package com.health.openscale.ui.screen.settings
import androidx.activity.result.launch
import androidx.navigation.NavController
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.health.openscale.R
import com.health.openscale.ui.screen.SharedViewModel
import kotlinx.coroutines.launch
@Composable
fun ChartSettingsScreen(
navController: NavController,
sharedViewModel: SharedViewModel,
settingsViewModel: SettingsViewModel
) {
val chartSettingsScreenTitle = stringResource(R.string.settings_item_chart)
LaunchedEffect(Unit) {
sharedViewModel.setTopBarTitle(chartSettingsScreenTitle)
}
val coroutineScope = rememberCoroutineScope()
val showDataPoints by sharedViewModel.userSettingRepository.showChartDataPoints.collectAsState(true)
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = stringResource(R.string.setting_show_chart_points),
style = MaterialTheme.typography.bodyLarge
)
Switch(
checked = showDataPoints,
onCheckedChange = { newValue ->
coroutineScope.launch {
sharedViewModel.userSettingRepository.setShowChartDataPoints(newValue)
}
}
)
}
}
}

View File

@@ -23,10 +23,12 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ShowChart
import androidx.compose.material.icons.filled.Bluetooth
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.ShowChart
import androidx.compose.material.icons.filled.Storage
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.Card
@@ -79,6 +81,7 @@ fun SettingsScreen(
val userSettingsLabel = stringResource(R.string.settings_item_user)
val measurementTypesLabel = stringResource(R.string.settings_item_measurement_types)
val bluetoothLabel = stringResource(R.string.settings_item_bluetooth)
val chartSettingsLabel = stringResource(R.string.settings_item_chart)
val dataManagementLabel = stringResource(R.string.settings_item_data_management)
val aboutLabel = stringResource(R.string.settings_item_about)
@@ -107,6 +110,12 @@ fun SettingsScreen(
route = Routes.BLUETOOTH_SETTINGS,
contentDescription = bluetoothLabel
),
SettingsItem(
label = chartSettingsLabel,
icon = Icons.AutoMirrored.Filled.ShowChart,
route = Routes.CHART_SETTINGS,
contentDescription = chartSettingsLabel
),
SettingsItem(
label = dataManagementLabel,
icon = Icons.Filled.Storage,

View File

@@ -281,6 +281,7 @@
<string name="settings_item_user">Benutzer</string>
<string name="settings_item_measurement_types">Messarten</string>
<string name="settings_item_bluetooth">Bluetooth</string>
<string name="settings_item_chart">Diagramm</string>
<string name="settings_item_data_management">Datenverwaltung</string>
<string name="settings_item_about">Über</string>
@@ -288,6 +289,9 @@
<string name="settings_general_title">Allgemeine Einstellungen</string>
<string name="settings_language_label">Sprache</string>
<!-- Diagramm Einstellungen -->
<string name="setting_show_chart_points">Datenpunkte anzeigen</string>
<!-- Über-Bildschirm & Diagnose -->
<string name="version_info">Version: %1$s (%2$s)</string>
<string name="project_information_title">Projektinformationen</string>

View File

@@ -283,6 +283,7 @@
<string name="settings_item_user">User</string>
<string name="settings_item_measurement_types">Measurement Types</string>
<string name="settings_item_bluetooth">Bluetooth</string>
<string name="settings_item_chart">Chart</string>
<string name="settings_item_data_management">Data Management</string>
<string name="settings_item_about">About</string>
@@ -290,6 +291,9 @@
<string name="settings_general_title">General Settings</string>
<string name="settings_language_label">Language</string>
<!-- Chart Settings Screen -->
<string name="setting_show_chart_points">Show data points</string>
<!-- About Screen & Diagnostics -->
<string name="version_info">Version: %1$s (%2$s)</string>
<string name="project_information_title">Project Information</string>