Migrate to kotlinx datetime [2/2]
This commit is contained in:
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()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user