Refactor use of Java.util.date to Java.time.*, to fix localized date issues. (#402)

* Add support for localdate based relative times

* Update History Screen to use new localdate based relative times

* Update Updates Screen to use new localdate based relative times

* Cleaned up date util classes

* Updated build time display

* Code cleanup

* Fixed crash in settings

* Updated Preferences item

* Worker Info works

* Fixed Tracker date display

* Code changes to pass detekt
This commit is contained in:
Maddie Witman
2024-02-16 06:09:00 -05:00
committed by GitHub
parent 96c236e5c3
commit 7ff95e21ba
13 changed files with 89 additions and 100 deletions
@@ -5,7 +5,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.core.util.insertSeparators
import eu.kanade.presentation.history.HistoryUiModel
import eu.kanade.tachiyomi.util.lang.toDateKey
import eu.kanade.tachiyomi.util.lang.toLocalDate
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
@@ -28,7 +28,7 @@ import tachiyomi.domain.history.interactor.RemoveHistory
import tachiyomi.domain.history.model.HistoryWithRelations
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Date
import java.time.LocalDate
class HistoryScreenModel(
private val getHistory: GetHistory = Injekt.get(),
@@ -60,10 +60,12 @@ class HistoryScreenModel(
private fun List<HistoryWithRelations>.toHistoryUiModels(): List<HistoryUiModel> {
return map { HistoryUiModel.Item(it) }
.insertSeparators { before, after ->
val beforeDate = before?.item?.readAt?.time?.toDateKey() ?: Date(0)
val afterDate = after?.item?.readAt?.time?.toDateKey() ?: Date(0)
val beforeDate = before?.item?.readAt?.time?.toLocalDate() ?: LocalDate.MIN
val afterDate = after?.item?.readAt?.time?.toLocalDate() ?: LocalDate.MIN
when {
beforeDate.time != afterDate.time && afterDate.time != 0L -> HistoryUiModel.Header(afterDate)
beforeDate.isAfter(afterDate)
or afterDate.equals(LocalDate.MIN)
or beforeDate.equals(LocalDate.MIN) -> HistoryUiModel.Header(afterDate)
// Return null to avoid adding a separator between two items.
else -> null
}
@@ -16,7 +16,7 @@ import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.util.lang.toDateKey
import eu.kanade.tachiyomi.util.lang.toLocalDate
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentListOf
@@ -45,8 +45,8 @@ import tachiyomi.domain.updates.interactor.GetUpdates
import tachiyomi.domain.updates.model.UpdatesWithRelations
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.time.LocalDate
import java.time.ZonedDateTime
import java.util.Date
class UpdatesScreenModel(
private val sourceManager: SourceManager = Injekt.get(),
@@ -374,12 +374,12 @@ class UpdatesScreenModel(
return items
.map { UpdatesUiModel.Item(it) }
.insertSeparators { before, after ->
val beforeDate = before?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
val afterDate = after?.item?.update?.dateFetch?.toDateKey() ?: Date(0)
val beforeDate = before?.item?.update?.dateFetch?.toLocalDate() ?: LocalDate.MIN
val afterDate = after?.item?.update?.dateFetch?.toLocalDate() ?: LocalDate.MIN
when {
beforeDate.time != afterDate.time && afterDate.time != 0L -> {
UpdatesUiModel.Header(afterDate)
}
beforeDate.isAfter(afterDate)
or afterDate.equals(LocalDate.MIN)
or beforeDate.equals(LocalDate.MIN) -> UpdatesUiModel.Header(afterDate)
// Return null to avoid adding a separator between two items.
else -> null
}
@@ -6,15 +6,17 @@ import tachiyomi.core.common.i18n.stringResource
import tachiyomi.i18n.MR
import java.text.DateFormat
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.temporal.ChronoUnit
import java.util.Calendar
import java.util.Date
fun Date.toDateTimestampString(dateFormatter: DateFormat): String {
val date = dateFormatter.format(this)
val time = DateFormat.getTimeInstance(DateFormat.SHORT).format(this)
fun LocalDateTime.toDateTimestampString(dateTimeFormatter: DateTimeFormatter): String {
val date = dateTimeFormatter.format(this)
val time = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(this)
return "$date $time"
}
@@ -32,52 +34,28 @@ fun Long.convertEpochMillisZone(
.toEpochMilli()
}
/**
* Get date as time key
*
* @param date desired date
* @return date as time key
*/
fun Long.toDateKey(): Date {
val instant = Instant.ofEpochMilli(this)
return Date.from(instant.truncatedTo(ChronoUnit.DAYS))
fun Long.toLocalDate(): LocalDate {
return LocalDate.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
}
fun Date.toRelativeString(
fun LocalDate.toRelativeSting(
context: Context,
relative: Boolean = true,
dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.SHORT),
dateFormat: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT),
): String {
if (!relative) {
return dateFormat.format(this)
}
val now = Date()
val difference = now.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY) -
this.timeWithOffset.floorNearest(MILLISECONDS_IN_DAY)
val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt()
val now = LocalDate.now()
val difference = ChronoUnit.DAYS.between(this, now)
return when {
difference < 0 -> dateFormat.format(this)
difference < MILLISECONDS_IN_DAY -> context.stringResource(MR.strings.relative_time_today)
difference < MILLISECONDS_IN_DAY.times(7) -> context.pluralStringResource(
difference < 0 -> difference.toString()
difference < 1 -> context.stringResource(MR.strings.relative_time_today)
difference < 7 -> context.pluralStringResource(
MR.plurals.relative_time,
days,
days,
difference.toInt(),
difference.toInt(),
)
else -> dateFormat.format(this)
}
}
private const val MILLISECONDS_IN_DAY = 86_400_000L
private val Date.timeWithOffset: Long
get() {
return Calendar.getInstance().run {
time = this@timeWithOffset
val dstOffset = get(Calendar.DST_OFFSET)
this@timeWithOffset.time + timeZone.rawOffset + dstOffset
}
}
private fun Long.floorNearest(to: Long): Long {
return this.floorDiv(to) * to
}