refactor(utils): use time formats from resources to enable localization

Closes: #151
This commit is contained in:
Nishant Mishra
2025-11-29 15:53:32 +05:30
parent 1e451041fb
commit 8d77333fec
5 changed files with 81 additions and 40 deletions

View File

@@ -32,7 +32,6 @@ import androidx.compose.ui.unit.dp
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
@Composable
fun ColumnScope.ProductivityGraph(
@@ -53,6 +52,9 @@ fun ColumnScope.ProductivityGraph(
Spacer(Modifier.height(8.dp))
TimeColumnChart(
modelProducer,
hoursFormat = stringResource(R.string.hours_format),
hoursMinutesFormat = stringResource(R.string.hours_and_minutes_format),
minutesFormat = stringResource(R.string.minutes_format),
axisTypeface = axisTypeface,
markerTypeface = markerTypeface,
xValueFormatter = CartesianValueFormatter { _, value, _ ->
@@ -63,9 +65,6 @@ fun ColumnScope.ProductivityGraph(
3.0 -> "18 - 24"
else -> ""
}
},
yValueFormatter = CartesianValueFormatter { _, value, _ ->
millisecondsToHoursMinutes(value.toLong())
}
)
}

View File

@@ -130,6 +130,10 @@ fun StatsScreen(
) {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val hoursFormat = stringResource(R.string.hours_format)
val hoursMinutesFormat = stringResource(R.string.hours_and_minutes_format)
val minutesFormat = stringResource(R.string.minutes_format)
var lastWeekStatExpanded by rememberSaveable { mutableStateOf(false) }
var lastMonthStatExpanded by rememberSaveable { mutableStateOf(false) }
@@ -223,7 +227,10 @@ fun StatsScreen(
)
Text(
remember(todayStat) {
millisecondsToHoursMinutes(todayStat?.totalFocusTime() ?: 0)
millisecondsToHoursMinutes(
todayStat?.totalFocusTime() ?: 0,
hoursMinutesFormat
)
},
style = typography.displaySmall,
color = colorScheme.onPrimaryContainer,
@@ -249,7 +256,10 @@ fun StatsScreen(
)
Text(
remember(todayStat) {
millisecondsToHoursMinutes(todayStat?.breakTime ?: 0)
millisecondsToHoursMinutes(
todayStat?.breakTime ?: 0,
hoursMinutesFormat
)
},
style = typography.displaySmall,
color = colorScheme.onTertiaryContainer,
@@ -282,7 +292,8 @@ fun StatsScreen(
millisecondsToHoursMinutes(
remember(lastWeekAverageFocusTimes) {
lastWeekAverageFocusTimes.sum().toLong()
}
},
hoursMinutesFormat
),
style = typography.displaySmall
)
@@ -295,7 +306,10 @@ fun StatsScreen(
}
item {
TimeColumnChart(
lastWeekSummaryChartData.first,
modelProducer = lastWeekSummaryChartData.first,
hoursFormat = hoursFormat,
hoursMinutesFormat = hoursMinutesFormat,
minutesFormat = minutesFormat,
modifier = Modifier.padding(start = 16.dp),
axisTypeface = axisTypeface,
markerTypeface = markerTypeface,
@@ -361,7 +375,8 @@ fun StatsScreen(
millisecondsToHoursMinutes(
remember(lastMonthAverageFocusTimes) {
lastMonthAverageFocusTimes.sum().toLong()
}
},
hoursMinutesFormat
),
style = typography.displaySmall
)
@@ -374,7 +389,10 @@ fun StatsScreen(
}
item {
TimeColumnChart(
lastMonthSummaryChartData.first,
modelProducer = lastMonthSummaryChartData.first,
hoursFormat = hoursFormat,
hoursMinutesFormat = hoursMinutesFormat,
minutesFormat = minutesFormat,
modifier = Modifier.padding(start = 16.dp),
axisTypeface = axisTypeface,
markerTypeface = markerTypeface,
@@ -441,7 +459,8 @@ fun StatsScreen(
millisecondsToHoursMinutes(
remember(lastYearAverageFocusTimes) {
lastYearAverageFocusTimes.sum().toLong()
}
},
hoursMinutesFormat
),
style = typography.displaySmall
)
@@ -454,7 +473,10 @@ fun StatsScreen(
}
item {
TimeLineChart(
lastYearSummaryChartData.first,
modelProducer = lastYearSummaryChartData.first,
hoursFormat = hoursFormat,
hoursMinutesFormat = hoursMinutesFormat,
minutesFormat = minutesFormat,
modifier = Modifier.padding(start = 16.dp),
axisTypeface = axisTypeface,
markerTypeface = markerTypeface,

View File

@@ -68,6 +68,9 @@ import org.nsh07.pomodoro.utils.millisecondsToMinutes
@Composable
fun TimeColumnChart(
modelProducer: CartesianChartModelProducer,
hoursFormat: String,
hoursMinutesFormat: String,
minutesFormat: String,
modifier: Modifier = Modifier,
axisTypeface: Typeface = Typeface.DEFAULT,
markerTypeface: Typeface = Typeface.DEFAULT,
@@ -76,9 +79,9 @@ fun TimeColumnChart(
xValueFormatter: CartesianValueFormatter = CartesianValueFormatter.Default,
yValueFormatter: CartesianValueFormatter = CartesianValueFormatter { _, value, _ ->
if (value >= 60 * 60 * 1000) {
millisecondsToHours(value.toLong())
millisecondsToHours(value.toLong(), hoursFormat)
} else {
millisecondsToMinutes(value.toLong())
millisecondsToMinutes(value.toLong(), minutesFormat)
}
},
markerValueFormatter: DefaultCartesianMarker.ValueFormatter = DefaultCartesianMarker.ValueFormatter { _, targets ->
@@ -88,9 +91,9 @@ fun TimeColumnChart(
} else 0L
if (value >= 60 * 60 * 1000) {
millisecondsToHoursMinutes(value)
millisecondsToHoursMinutes(value, hoursMinutesFormat)
} else {
millisecondsToMinutes(value)
millisecondsToMinutes(value, minutesFormat)
}
},
animationSpec: AnimationSpec<Float>? = null
@@ -179,7 +182,13 @@ private fun TimeColumnChartPreview() {
}
TomatoTheme {
Surface {
TimeColumnChart(thickness = 8.dp, modelProducer = modelProducer)
TimeColumnChart(
thickness = 8.dp,
modelProducer = modelProducer,
hoursFormat = "%dh",
hoursMinutesFormat = "%dh %dm",
minutesFormat = "%dm"
)
}
}
}

View File

@@ -74,6 +74,9 @@ import org.nsh07.pomodoro.utils.millisecondsToMinutes
@Composable
fun TimeLineChart(
modelProducer: CartesianChartModelProducer,
hoursFormat: String,
hoursMinutesFormat: String,
minutesFormat: String,
modifier: Modifier = Modifier,
axisTypeface: Typeface = Typeface.DEFAULT,
markerTypeface: Typeface = Typeface.DEFAULT,
@@ -82,9 +85,9 @@ fun TimeLineChart(
xValueFormatter: CartesianValueFormatter = CartesianValueFormatter.Default,
yValueFormatter: CartesianValueFormatter = CartesianValueFormatter { _, value, _ ->
if (value >= 60 * 60 * 1000) {
millisecondsToHours(value.toLong())
millisecondsToHours(value.toLong(), hoursFormat)
} else {
millisecondsToMinutes(value.toLong())
millisecondsToMinutes(value.toLong(), minutesFormat)
}
},
markerValueFormatter: DefaultCartesianMarker.ValueFormatter = DefaultCartesianMarker.ValueFormatter { _, targets ->
@@ -94,9 +97,9 @@ fun TimeLineChart(
} else 0L
if (value >= 60 * 60 * 1000) {
millisecondsToHoursMinutes(value)
millisecondsToHoursMinutes(value, hoursMinutesFormat)
} else {
millisecondsToMinutes(value)
millisecondsToMinutes(value, minutesFormat)
}
},
animationSpec: AnimationSpec<Float>? = null
@@ -203,7 +206,12 @@ private fun TimeLineChartPreview() {
}
TomatoTheme {
Surface {
TimeLineChart(modelProducer = modelProducer)
TimeLineChart(
modelProducer = modelProducer,
hoursFormat = "%dh",
hoursMinutesFormat = "%dh %dm",
minutesFormat = "%dm"
)
}
}
}

View File

@@ -22,25 +22,40 @@
<string name="always_on_display">Always On Display</string>
<string name="always_on_display_desc">Tap anywhere when viewing the timer to switch to AOD mode</string>
<string name="app_name">Tomato</string>
<string name="app_name_plus">Tomato+</string>
<string name="appearance">Appearance</string>
<string name="black_theme">Black theme</string>
<string name="black_theme_desc">Use a pure black dark theme</string>
<string name="bmc">BuyMeACoffee</string>
<string name="break_">Break</string>
<string name="choose_color_scheme">Choose color scheme</string>
<string name="choose_language">Choose language</string>
<string name="choose_theme">Choose theme</string>
<string name="color">Color</string>
<string name="color_scheme">Color scheme</string>
<string name="completed">Completed</string>
<string name="dark">Dark</string>
<string name="dnd">Do Not Disturb</string>
<string name="dnd_desc">Turn on DND when running a Focus timer</string>
<string name="durations">Durations</string>
<string name="dynamic">Dynamic</string>
<string name="dynamic_color">Dynamic color</string>
<string name="dynamic_color_desc">Adapt theme colors from your wallpaper</string>
<string name="exit">Exit</string>
<string name="focus">Focus</string>
<string name="focus_per_day_avg">focus per day (avg)</string>
<string name="get_plus">Get Tomato+</string>
<string name="help_with_translation">Help with translation</string>
<string name="hours_and_minutes_format">%dh %dm</string>
<string name="hours_format">%dh</string>
<string name="language">Language</string>
<string name="last_month">Last month</string>
<string name="last_week">Last week</string>
<string name="last_year">Last year</string>
<string name="light">Light</string>
<string name="long_break">Long break</string>
<string name="min_remaining_notification">%1$s min remaining</string>
<string name="minutes_format">%dm</string>
<string name="monthly_productivity_analysis">Monthly productivity analysis</string>
<string name="more">More</string>
<string name="more_info">More info</string>
@@ -51,13 +66,16 @@
<string name="pomodoro_info">A \"session\" is a sequence of pomodoro intervals that contain focus intervals, short break intervals, and a long break interval. The last break of a session is always a long break.</string>
<string name="productivity_analysis">Productivity analysis</string>
<string name="productivity_analysis_desc">Focus durations at different times of the day</string>
<string name="rate_on_google_play">Rate on Google Play</string>
<string name="restart">Restart</string>
<string name="selected">Selected</string>
<string name="session_length">Session length</string>
<string name="session_length_desc">Focus intervals in one session: %1$d</string>
<string name="settings">Settings</string>
<string name="short_break">Short break</string>
<string name="skip">Skip</string>
<string name="skip_to_next">Skip to next</string>
<string name="sound">Sound</string>
<string name="start">Start</string>
<string name="start_next">Start next</string>
<string name="stats">Stats</string>
@@ -70,28 +88,13 @@
<string name="timer">Timer</string>
<string name="timer_progress">Timer progress</string>
<string name="timer_session_count">%1$d of %2$d</string>
<string name="timer_settings_reset_info">Reset the timer to change settings</string>
<string name="today">Today</string>
<string name="tomato_foss">Tomato FOSS</string>
<string name="tomato_foss_desc">All features are unlocked in this version. If my app made a difference in your life, please consider supporting me by donating on %1$s.</string>
<string name="up_next">Up next</string>
<string name="up_next_notification">Up next: %1$s (%2$s)</string>
<string name="vibrate">Vibration</string>
<string name="vibrate_desc">Vibrate when a timer completes</string>
<string name="weekly_productivity_analysis">Weekly productivity analysis</string>
<string name="appearance">Appearance</string>
<string name="durations">Durations</string>
<string name="sound">Sound</string>
<string name="dnd">Do Not Disturb</string>
<string name="dnd_desc">Turn on DND when running a Focus timer</string>
<string name="app_name_plus">Tomato+</string>
<string name="get_plus">Get Tomato+</string>
<string name="dynamic_color">Dynamic color</string>
<string name="dynamic_color_desc">Adapt theme colors from your wallpaper</string>
<string name="tomato_foss">Tomato FOSS</string>
<string name="tomato_foss_desc">All features are unlocked in this version. If my app made a difference in your life, please consider supporting me by donating on %1$s.</string>
<string name="language">Language</string>
<string name="choose_language">Choose language</string>
<string name="rate_on_google_play">Rate on Google Play</string>
<string name="bmc">BuyMeACoffee</string>
<string name="selected">Selected</string>
<string name="help_with_translation">Help with translation</string>
<string name="timer_settings_reset_info">Reset the timer to change settings</string>
</resources>