|
19 | 19 |
|
20 | 20 | package com.github.quarck.calnotify.prefs |
21 | 21 |
|
| 22 | +import android.content.Context |
22 | 23 | import com.github.quarck.calnotify.Consts |
| 24 | +import com.github.quarck.calnotify.R |
23 | 25 |
|
24 | 26 | object PreferenceUtils { |
25 | 27 |
|
@@ -115,10 +117,55 @@ object PreferenceUtils { |
115 | 117 | fun formatPattern(pattern: LongArray): String = |
116 | 118 | pattern.map { p -> formatSnoozePreset(p) }.joinToString(", ") |
117 | 119 |
|
| 120 | + data class NormalizeResult(val value: String, val droppedCount: Int) |
| 121 | + |
118 | 122 | /** |
119 | | - * Format a millisecond duration as a human-readable label (e.g., "8 hours", "3 days", "1 week"). |
120 | | - * Used for display in bottom sheets and chips. |
| 123 | + * Parse and normalize a comma-separated preset string. |
| 124 | + * Returns null if parsing failed entirely. |
| 125 | + * [filter] removes individual millis values that don't pass (e.g., negative, over max). |
| 126 | + * [droppedCount] in the result indicates how many values were removed by the filter. |
121 | 127 | */ |
| 128 | + fun normalizePresetInput(value: String, defaultValue: String, filter: ((Long) -> Boolean)? = null): NormalizeResult? { |
| 129 | + val presets = parseSnoozePresets(value) ?: return null |
| 130 | + val tokens = value.split(',').map { it.trim() }.filter { it.isNotEmpty() } |
| 131 | + val totalCount = tokens.size |
| 132 | + val kept = if (filter != null) { |
| 133 | + tokens.zip(presets.toList()).filter { (_, millis) -> filter(millis) }.map { it.first } |
| 134 | + } else { |
| 135 | + tokens |
| 136 | + } |
| 137 | + if (kept.isEmpty()) return NormalizeResult(defaultValue, totalCount) |
| 138 | + return NormalizeResult(kept.joinToString(", "), totalCount - kept.size) |
| 139 | + } |
| 140 | + |
| 141 | + /** |
| 142 | + * Format a millisecond duration as a localizable human-readable label using Android plural resources. |
| 143 | + * Prefer this over the non-Context overload for user-facing text. |
| 144 | + */ |
| 145 | + fun formatPresetHumanReadable(context: Context, millis: Long): String { |
| 146 | + val seconds = millis / 1000L |
| 147 | + val res = context.resources |
| 148 | + |
| 149 | + if (seconds % Consts.WEEK_IN_SECONDS == 0L) { |
| 150 | + val n = (seconds / Consts.WEEK_IN_SECONDS).toInt() |
| 151 | + return res.getQuantityString(R.plurals.duration_weeks, n, n) |
| 152 | + } |
| 153 | + if (seconds % Consts.DAY_IN_SECONDS == 0L) { |
| 154 | + val n = (seconds / Consts.DAY_IN_SECONDS).toInt() |
| 155 | + return res.getQuantityString(R.plurals.duration_days, n, n) |
| 156 | + } |
| 157 | + if (seconds % Consts.HOUR_IN_SECONDS == 0L) { |
| 158 | + val n = (seconds / Consts.HOUR_IN_SECONDS).toInt() |
| 159 | + return res.getQuantityString(R.plurals.duration_hours, n, n) |
| 160 | + } |
| 161 | + if (seconds % Consts.MINUTE_IN_SECONDS == 0L) { |
| 162 | + val n = (seconds / Consts.MINUTE_IN_SECONDS).toInt() |
| 163 | + return res.getQuantityString(R.plurals.duration_minutes, n, n) |
| 164 | + } |
| 165 | + return res.getQuantityString(R.plurals.duration_seconds, seconds.toInt(), seconds.toInt()) |
| 166 | + } |
| 167 | + |
| 168 | + /** Non-Context fallback — English-only. Prefer the Context overload for user-facing text. */ |
122 | 169 | fun formatPresetHumanReadable(millis: Long): String { |
123 | 170 | val seconds = millis / 1000L |
124 | 171 |
|
|
0 commit comments