Fix DateTimeAgo formatting

This commit is contained in:
Koitharu
2025-02-09 17:40:28 +02:00
parent 28ae785142
commit 5f0514638a
4 changed files with 43 additions and 29 deletions

View File

@@ -1,17 +1,18 @@
package org.koitharu.kotatsu.core.ui.model package org.koitharu.kotatsu.core.ui.model
import android.content.res.Resources import android.content.Context
import android.text.format.DateUtils
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.toMillis
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter
sealed class DateTimeAgo { sealed class DateTimeAgo {
abstract fun format(resources: Resources): String abstract fun format(context: Context): String
object JustNow : DateTimeAgo() { object JustNow : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.just_now) return context.getString(R.string.just_now)
} }
override fun toString() = "just_now" override fun toString() = "just_now"
@@ -20,24 +21,32 @@ sealed class DateTimeAgo {
} }
data class MinutesAgo(val minutes: Int) : DateTimeAgo() { data class MinutesAgo(val minutes: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.minutes_ago, minutes, minutes) return context.resources.getQuantityString(
R.plurals.minutes_ago,
minutes,
minutes,
)
} }
override fun toString() = "minutes_ago_$minutes" override fun toString() = "minutes_ago_$minutes"
} }
data class HoursAgo(val hours: Int) : DateTimeAgo() { data class HoursAgo(val hours: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.hours_ago, hours, hours) return context.resources.getQuantityString(
R.plurals.hours_ago,
hours,
hours,
)
} }
override fun toString() = "hours_ago_$hours" override fun toString() = "hours_ago_$hours"
} }
object Today : DateTimeAgo() { object Today : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.today) return context.getString(R.string.today)
} }
override fun toString() = "today" override fun toString() = "today"
@@ -46,8 +55,8 @@ sealed class DateTimeAgo {
} }
object Yesterday : DateTimeAgo() { object Yesterday : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.yesterday) return context.getString(R.string.yesterday)
} }
override fun toString() = "yesterday" override fun toString() = "yesterday"
@@ -56,44 +65,46 @@ sealed class DateTimeAgo {
} }
data class DaysAgo(val days: Int) : DateTimeAgo() { data class DaysAgo(val days: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.days_ago, days, days) return context.resources.getQuantityString(R.plurals.days_ago, days, days)
} }
override fun toString() = "days_ago_$days" override fun toString() = "days_ago_$days"
} }
data class MonthsAgo(val months: Int) : DateTimeAgo() { data class MonthsAgo(val months: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return if (months == 0) { return if (months == 0) {
resources.getString(R.string.this_month) context.getString(R.string.this_month)
} else { } else {
resources.getQuantityString(R.plurals.months_ago, months, months) context.resources.getQuantityString(
R.plurals.months_ago,
months,
months,
)
} }
} }
} }
data class Absolute(private val date: LocalDate) : DateTimeAgo() { data class Absolute(private val date: LocalDate) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return if (date == EPOCH_DATE) { return if (date == EPOCH_DATE) {
resources.getString(R.string.unknown) context.getString(R.string.unknown)
} else { } else {
date.format(formatter) DateUtils.formatDateTime(context, date.toMillis(), DateUtils.FORMAT_SHOW_DATE)
} }
} }
override fun toString() = "abs_${date.toEpochDay()}" override fun toString() = "abs_${date.toEpochDay()}"
companion object { private companion object {
// TODO: Use Java 9's LocalDate.EPOCH. val EPOCH_DATE: LocalDate = LocalDate.of(1970, 1, 1)
private val EPOCH_DATE = LocalDate.of(1970, 1, 1)
private val formatter = DateTimeFormatter.ofPattern("d MMMM")
} }
} }
object LongAgo : DateTimeAgo() { object LongAgo : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.long_ago) return context.getString(R.string.long_ago)
} }
override fun toString() = "long_ago" override fun toString() = "long_ago"

View File

@@ -35,6 +35,7 @@ fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo
} }
} }
@Suppress("KotlinConstantConditions")
fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this) fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this)
fun Resources.formatDurationShort(millis: Long): String? { fun Resources.formatDurationShort(millis: Long): String? {
@@ -50,3 +51,5 @@ fun Resources.formatDurationShort(millis: Long): String? {
else -> getString(R.string.seconds_short, seconds) else -> getString(R.string.seconds_short, seconds)
} }
} }
fun LocalDate.toMillis(): Long = atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()

View File

@@ -36,7 +36,7 @@ data class ListHeader private constructor(
fun getText(context: Context): CharSequence? = when (textRaw) { fun getText(context: Context): CharSequence? = when (textRaw) {
is CharSequence -> textRaw is CharSequence -> textRaw
is Int -> if (textRaw != 0) context.getString(textRaw) else null is Int -> if (textRaw != 0) context.getString(textRaw) else null
is DateTimeAgo -> textRaw.format(context.resources) is DateTimeAgo -> textRaw.format(context)
else -> null else -> null
} }

View File

@@ -32,7 +32,7 @@ class MangaStatsSheet : BaseAdaptiveSheet<SheetStatsMangaBinding>(), View.OnClic
binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga) binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga)
viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged) viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged)
viewModel.startDate.observe(viewLifecycleOwner) { viewModel.startDate.observe(viewLifecycleOwner) {
binding.textViewStart.textAndVisible = it?.format(resources) binding.textViewStart.textAndVisible = it?.format(binding.root.context)
} }
viewModel.totalPagesRead.observe(viewLifecycleOwner) { viewModel.totalPagesRead.observe(viewLifecycleOwner) {
binding.textViewPages.text = getString(R.string.pages_read_s, it.format()) binding.textViewPages.text = getString(R.string.pages_read_s, it.format())