M6b: core:design fixes after the M7 wave

Bugs: viewerPercentOf reads basis points (Samples in bp); FullSplitPicker and the
split labels use editor_split_full_on_you ("Allt på dig"); AmountInput.of restores
money with both decimals (AmountInput.percent for ratio fields), replacing M7c's
moneyInput; quickRowCategories does the D-060 fill itself; KvittScaffold resolves
resource-backed snackbars (showKvittSnackbar) while shown.

Gaps: ConfirmDialog optional and styled body; KvittButton loading form (M7a uses it,
ProgressBottomButton removed); InviteCodeField wraps after a group, placeholder,
imeAction; EmptyState icon tile and actionEnabled; DateFormatter.monthName and
dayRangeLong; AnalyticsFilterBar periodOwnRow; segmentedItem builder; screen tokens
in KvittDimens (OnboardingDimens removed); common_ok, common_undo; module-proposed
keys recorded in strings.csv; quick-row labels end in an ellipsis on line two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 11:35:06 +02:00
parent c4ab35f66e
commit b24c8b5ba3
49 changed files with 655 additions and 261 deletions
@@ -58,6 +58,7 @@ import se.hagstedt.kvitt.model.Granularity
import se.hagstedt.kvitt.model.GroupBy
import se.hagstedt.kvitt.model.GroupKey
import se.hagstedt.kvitt.model.Measure
import se.hagstedt.kvitt.model.RangePreset
import se.hagstedt.kvitt.core.design.R as DesignR
/**
@@ -141,13 +142,15 @@ private fun Filters(state: AnalyticsUiState, events: AnalyticsEvents) {
listOf(stringResource(R.string.analytics_group_by_category), stringResource(R.string.analytics_group_by_account)),
GroupBy.entries.indexOf(filter.groupBy),
) { events.onGroupBy(GroupBy.entries[it]) },
// A custom range label ("Anpassad · 24 aug.–17 okt.") gets a row of its own (design frame S-11-analytics-week).
periodOwnRow = filter.preset == RangePreset.CUSTOM,
)
}
/** The range caption: "maj–okt 2026 · Hushållet", or "24 aug.–17 okt. · 8 veckor" in week granularity. */
@Composable
private fun totalCaption(data: AnalyticsState): String {
val range = rangeText(data.start, data.end, data.filter, LocalKvittClock.current.today, kvittLanguage())
val range = rangeText(data.start, data.end, data.filter, LocalKvittClock.current.today, kvittLanguage(), long = true)
val second = when {
data.filter.granularity == Granularity.WEEK -> pluralStringResource(R.plurals.analytics_weeks, data.buckets.size, data.buckets.size)
data.filter.measure == Measure.HOUSEHOLD -> stringResource(R.string.analytics_measure_household)
@@ -192,7 +195,7 @@ private fun Ready(content: AnalyticsContent.Ready, events: AnalyticsEvents, open
private fun OverTime(content: AnalyticsContent.Ready, onBucket: (String) -> Unit) {
val data = content.data
val groups = chartGroups(data, content.categories, content.accounts)
val range = rangeText(data.start, data.end, data.filter, LocalKvittClock.current.today, kvittLanguage())
val range = rangeText(data.start, data.end, data.filter, LocalKvittClock.current.today, kvittLanguage(), long = true)
val highest = data.buckets.maxByOrNull { it.totalOre }
val lowest = data.buckets.minByOrNull { it.totalOre }
val summary = if (highest != null && lowest != null) {
@@ -31,14 +31,18 @@ internal fun presetLabel(preset: RangePreset): Int = when (preset) {
internal fun measureLabel(measure: Measure): Int =
if (measure == Measure.HOUSEHOLD) R.string.analytics_measure_household else R.string.analytics_measure_my_share
/** The range in a caption: whole months "maj–okt 2026" for a month preset, else days "24 aug.–17 okt.". */
internal fun rangeText(start: String, end: String, filter: AnalyticsFilter, today: LocalDate, language: KvittLanguage): String {
/**
* The range in a title or caption: whole months "maj–okt 2026" for a month preset, else days: short "24 aug.–17 okt."
* or, with [long] (the total card caption and the chart summary, design frame S-11-analytics-week), written out with the
* year "24 augusti–17 oktober 2026" (`DateFormatter.dayRangeLong`).
*/
internal fun rangeText(start: String, end: String, filter: AnalyticsFilter, today: LocalDate, language: KvittLanguage, long: Boolean = false): String {
val first = LocalDate.parse(start)
val last = LocalDate.parse(end)
return if (filter.granularity == Granularity.MONTH && filter.preset != RangePreset.CUSTOM) {
DateFormatter.monthRange(first, last, language)
} else {
DateFormatter.dayRange(first, last, today, language)
return when {
filter.granularity == Granularity.MONTH && filter.preset != RangePreset.CUSTOM -> DateFormatter.monthRange(first, last, language)
long -> DateFormatter.dayRangeLong(first, last, language)
else -> DateFormatter.dayRange(first, last, today, language)
}
}
@@ -42,12 +42,8 @@
<item quantity="one">%d utgift</item>
<item quantity="other">%d utgifter</item>
</plurals>
<!-- proposed (M7e): radio-group name of the month/week toggle -->
<string name="analytics_granularity">Indelning</string>
<!-- proposed (M7e): radio-group name of the measure toggle -->
<string name="analytics_measure">Mått</string>
<!-- proposed (M7e): radio-group name of the group-by toggle -->
<string name="analytics_group_by">Gruppera efter</string>
<!-- proposed (M7e): confirm button of the custom range picker -->
<string name="analytics_range_apply">Använd</string>
</resources>
@@ -42,12 +42,8 @@
<item quantity="one">%d expense</item>
<item quantity="other">%d expenses</item>
</plurals>
<!-- proposed (M7e): radio-group name of the month/week toggle -->
<string name="analytics_granularity">Interval</string>
<!-- proposed (M7e): radio-group name of the measure toggle -->
<string name="analytics_measure">Measure</string>
<!-- proposed (M7e): radio-group name of the group-by toggle -->
<string name="analytics_group_by">Group by</string>
<!-- proposed (M7e): confirm button of the custom range picker -->
<string name="analytics_range_apply">Apply</string>
</resources>