Migrate to kotlinx datetime [2/2]

This commit is contained in:
FooIbar committed 2024-03-02 17:58:37 +08:00
1 parent 5cf5cc5e34
commit 32887acecd
7 files changed
+144 -77

No files matched your search

@@ -53,7 +53,6 @@ import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.Crash
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.isAtLeastP
import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.isAtLeastS
@@ -105,7 +104,6 @@ class EhApplication : Application(), SingletonImageLoader.Factory {
}
super.onCreate()
System.loadLibrary("ehviewer")
ReadableTime.initialize(this)
lifecycleScope.launchIO {
launch {
EhTagDatabase
@@ -38,15 +38,15 @@ import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.client.exception.PiningException
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.util.ExceptionUtils
import com.hippo.ehviewer.util.toEpochMillis
import com.hippo.ehviewer.util.toFloatOrDefault
import com.hippo.ehviewer.util.toIntOrDefault
import com.hippo.ehviewer.util.trimAnd
import com.hippo.ehviewer.util.unescapeXml
import eu.kanade.tachiyomi.util.system.logcat
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.format.MonthNames
import kotlinx.datetime.format.char
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
@@ -78,8 +78,19 @@ object GalleryDetailParser {
private val PATTERN_FAVORITE_SLOT =
Regex("/fav.png\\); background-position:0px -(\\d+)px")
private val EMPTY_GALLERY_COMMENT_LIST = GalleryCommentList(emptyList(), false)
private val WEB_COMMENT_DATE_FORMAT = DateTimeFormatter
.ofPattern("dd MMMM yyyy, HH:mm", Locale.US).withZone(ZoneOffset.UTC)
// dd MMMM yyyy, HH:mm
private val WEB_COMMENT_DATE_FORMAT = LocalDateTime.Format {
dayOfMonth()
char(' ')
monthName(MonthNames.ENGLISH_FULL)
char(' ')
year()
chars(", ")
hour()
char(':')
minute()
}
private const val OFFENSIVE_STRING =
"<p>(And if you choose to ignore this warning, you lose all rights to complain about it in the future.)</p>"
private const val PINING_STRING = "<p>This gallery is pining for the fjords.</p>"
@@ -378,7 +389,7 @@ object GalleryDetailParser {
} else {
temp.substring("Posted on ".length) to null
}
val time = Instant.from(WEB_COMMENT_DATE_FORMAT.parse(timeStr)).toEpochMilli()
val time = WEB_COMMENT_DATE_FORMAT.parse(timeStr).toEpochMillis()
// comment
val c6 = element.getElementsByClass("c6").first()
// fix underline support
@@ -397,7 +408,7 @@ object GalleryDetailParser {
}
// last edited
val c8 = element.getElementsByClass("c8").first()
val lastEdited = c8?.children()?.first()?.run { Instant.from(WEB_COMMENT_DATE_FORMAT.parse(text())).toEpochMilli() } ?: 0
val lastEdited = c8?.children()?.first()?.run { WEB_COMMENT_DATE_FORMAT.parse(text()).toEpochMillis() } ?: 0
GalleryComment(
id, score, editable, voteUpAble, voteUpEd, voteDownAble,
voteDownEd, uploader, voteState, time, user, commentHtml, lastEdited,
@@ -16,20 +16,29 @@
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.util.toIntOrDefault
import com.hippo.ehviewer.util.toLocalDateTime
import com.hippo.ehviewer.util.toLongOrDefault
import com.hippo.ehviewer.util.unescapeXml
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.format.char
object ParserUtils {
private val formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm", Locale.US).withZone(ZoneOffset.UTC)
// yyyy-MM-dd HH:mm
private val formatter = LocalDateTime.Format {
year()
char('-')
monthNumber()
char('-')
dayOfMonth()
char(' ')
hour()
char(':')
minute()
}
@Synchronized
fun formatDate(time: Long): String {
return formatter.format(Instant.ofEpochMilli(time))
return formatter.format(time.toLocalDateTime())
}
fun trim(str: String?): String {
@@ -62,6 +62,7 @@ import com.hippo.ehviewer.util.isAtLeastT
import com.hippo.ehviewer.util.mapToLongArray
import com.hippo.ehviewer.util.requestPermission
import com.hippo.ehviewer.util.toEpochMillis
import com.hippo.ehviewer.util.toLocalDateTime
import com.hippo.unifile.UniFile
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
@@ -74,7 +75,6 @@ import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.minus
import kotlinx.datetime.toLocalDateTime
import kotlinx.datetime.todayIn
import moe.tarsin.coroutines.runSuspendCatching
import splitties.init.appCtx
@@ -439,8 +439,6 @@ suspend fun DialogState.showDatePicker(): String? {
}
},
)
val date = dateMillis?.let {
kotlinx.datetime.Instant.fromEpochMilliseconds(it).toLocalDateTime(TimeZone.UTC).date.toString()
}
val date = dateMillis?.run { toLocalDateTime().date.toString() }
return date
}
@@ -1,8 +1,18 @@
package com.hippo.ehviewer.util
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.atStartOfDayIn
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime
fun LocalDate.toEpochMillis(): Long =
atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds()
fun LocalDate.toEpochMillis(timeZone: TimeZone = TimeZone.UTC): Long =
atStartOfDayIn(timeZone).toEpochMilliseconds()
fun LocalDateTime.toEpochMillis(timeZone: TimeZone = TimeZone.UTC): Long =
toInstant(timeZone).toEpochMilliseconds()
fun Long.toLocalDateTime(timeZone: TimeZone = TimeZone.UTC): LocalDateTime =
Instant.fromEpochMilliseconds(this).toLocalDateTime(timeZone)
@@ -15,17 +15,20 @@
*/
package com.hippo.ehviewer.util
import android.content.Context
import android.content.res.Resources
import com.hippo.ehviewer.R
import java.time.Instant
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
import kotlinx.datetime.Clock
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.format.MonthNames
import kotlinx.datetime.format.Padding
import kotlinx.datetime.format.char
import kotlinx.datetime.toLocalDateTime
import splitties.init.appCtx
object ReadableTime {
private const val SECOND_MILLIS: Long = 1000
private const val SECOND_MILLIS = 1000L
private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
private const val DAY_MILLIS = 24 * HOUR_MILLIS
@@ -47,61 +50,101 @@ object ReadableTime {
R.plurals.second,
)
private val sCalendarLock = Any()
private val DATE_FORMAT_WITHOUT_YEAR = DateTimeFormatter.ofPattern("MMM d")
private val DATE_FORMAT_WITH_YEAR = DateTimeFormatter.ofPattern("MMM d, yyyy")
private val DATE_FORMAT_WITHOUT_YEAR_ZH = DateTimeFormatter.ofPattern("M月d日")
private val DATE_FORMAT_WITH_YEAR_ZH = DateTimeFormatter.ofPattern("yyyy年M月d日")
private val FILENAMABLE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss-SSS")
private val sDateFormatLock = Any()
private var sResources: Resources? = null
fun initialize(context: Context) {
sResources = context.applicationContext.resources
private val DATE_FORMAT_WITHOUT_YEAR = LocalDate.Format {
monthName(MonthNames.ENGLISH_ABBREVIATED)
char(' ')
dayOfMonth(Padding.NONE)
}
private val DATE_FORMAT_WITH_YEAR = LocalDate.Format {
monthName(MonthNames.ENGLISH_ABBREVIATED)
char(' ')
dayOfMonth(Padding.NONE)
chars(", ")
year()
}
private val DATE_FORMAT_WITHOUT_YEAR_ZH = LocalDate.Format {
monthNumber(Padding.NONE)
char('月')
dayOfMonth(Padding.NONE)
char('日')
}
private val DATE_FORMAT_WITH_YEAR_ZH = LocalDate.Format {
year()
char('年')
monthNumber(Padding.NONE)
char('月')
dayOfMonth(Padding.NONE)
char('日')
}
// yyyy-MM-dd-HH-mm-ss-SSS
private val FILENAMABLE_DATE_FORMAT = LocalDateTime.Format {
year()
char('-')
monthNumber()
char('-')
dayOfMonth()
char('-')
hour()
char('-')
minute()
char('-')
second()
char('-')
secondFraction(3)
}
private val sDateFormatLock = Any()
private val resources = appCtx.resources
fun getTimeAgo(time: Long): String {
val resources = sResources
val now = System.currentTimeMillis()
if (time > now + 2 * MINUTE_MILLIS || time <= 0) {
return resources!!.getString(R.string.from_the_future)
}
val nowInstant = Clock.System.now()
val now = nowInstant.toEpochMilliseconds()
val diff = now - time
if (diff < MINUTE_MILLIS) {
return resources!!.getString(R.string.just_now)
} else if (diff < 2 * MINUTE_MILLIS) {
return resources!!.getQuantityString(R.plurals.some_minutes_ago, 1, 1)
} else if (diff < 50 * MINUTE_MILLIS) {
val minutes = (diff / MINUTE_MILLIS).toInt()
return resources!!.getQuantityString(R.plurals.some_minutes_ago, minutes, minutes)
} else if (diff < 90 * MINUTE_MILLIS) {
return resources!!.getQuantityString(R.plurals.some_hours_ago, 1, 1)
} else if (diff < 24 * HOUR_MILLIS) {
val hours = (diff / HOUR_MILLIS).toInt()
return resources!!.getQuantityString(R.plurals.some_hours_ago, hours, hours)
} else if (diff < 48 * HOUR_MILLIS) {
return resources!!.getString(R.string.yesterday)
} else if (diff < WEEK_MILLIS) {
val days = (diff / DAY_MILLIS).toInt()
return resources!!.getString(R.string.some_days_ago, days)
} else {
synchronized(sCalendarLock) {
val nowDate = Instant.ofEpochMilli(now).atOffset(ZoneOffset.UTC)
val timeDate = Instant.ofEpochMilli(time).atOffset(ZoneOffset.UTC)
return when {
(diff < 0 || time <= 0) -> {
resources.getString(R.string.from_the_future)
}
diff < MINUTE_MILLIS -> {
resources.getString(R.string.just_now)
}
diff < 2 * MINUTE_MILLIS -> {
resources.getQuantityString(R.plurals.some_minutes_ago, 1, 1)
}
diff < 50 * MINUTE_MILLIS -> {
val minutes = (diff / MINUTE_MILLIS).toInt()
resources.getQuantityString(R.plurals.some_minutes_ago, minutes, minutes)
}
diff < 90 * MINUTE_MILLIS -> {
resources.getQuantityString(R.plurals.some_hours_ago, 1, 1)
}
diff < 24 * HOUR_MILLIS -> {
val hours = (diff / HOUR_MILLIS).toInt()
resources.getQuantityString(R.plurals.some_hours_ago, hours, hours)
}
diff < 48 * HOUR_MILLIS -> {
resources.getString(R.string.yesterday)
}
diff < WEEK_MILLIS -> {
val days = (diff / DAY_MILLIS).toInt()
resources.getString(R.string.some_days_ago, days)
}
else -> synchronized(sCalendarLock) {
val timeZone = TimeZone.currentSystemDefault()
val nowDate = nowInstant.toLocalDateTime(timeZone).date
val timeDate = time.toLocalDateTime(timeZone).date
val nowYear = nowDate.year
val timeYear = timeDate.year
val isZh = Locale.getDefault().language == "zh"
return if (nowYear == timeYear) {
(if (isZh) DATE_FORMAT_WITHOUT_YEAR_ZH else DATE_FORMAT_WITHOUT_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC))
if (nowYear == timeYear) {
if (isZh) DATE_FORMAT_WITHOUT_YEAR_ZH else DATE_FORMAT_WITHOUT_YEAR
} else {
(if (isZh) DATE_FORMAT_WITH_YEAR_ZH else DATE_FORMAT_WITH_YEAR)
.format(timeDate.toInstant().atOffset(ZoneOffset.UTC))
}
if (isZh) DATE_FORMAT_WITH_YEAR_ZH else DATE_FORMAT_WITH_YEAR
}.format(timeDate)
}
}
}
fun getShortTimeInterval(time: Long): String {
val resources = sResources
return buildString {
for (i in 0 until SIZE) {
val multiple = MULTIPLES[i]
@@ -109,7 +152,7 @@ object ReadableTime {
if (time > multiple * 1.5 || i == SIZE - 1) {
append(quotient)
.append(" ")
.append(resources!!.getQuantityString(UNITS[i], quotient.toInt()))
.append(resources.getQuantityString(UNITS[i], quotient.toInt()))
break
}
}
@@ -119,9 +162,7 @@ object ReadableTime {
fun getFilenamableTime(time: Long): String {
synchronized(sDateFormatLock) {
return FILENAMABLE_DATE_FORMAT.format(
Instant.ofEpochMilli(time).atZone(
ZoneId.systemDefault(),
),
time.toLocalDateTime(TimeZone.currentSystemDefault()),
)
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ compose-destinations = "1.10.1"
google-android-material = "1.12.0-alpha03"
kotlin = "2.0.0-Beta4"
kotlinx-coroutines = "1.8.0"
kotlinx-datetime = "0.5.0"
kotlinx-datetime = "0.6.0-RC"
kotlinx-serialization = "1.6.3"
ksp = "2.0.0-Beta4-1.0.18"
ktor = "3.0.0-beta-1"