Replace java.time APIs with kotlin(x).(date)time (#3001)
* Replace java.time APIs with kotlin(x).(date)time kotlinx-datetime explicitly says in its README that it does not cover i18n, so we have to stick with using their toJavaX converters wherever we localise dates and times. Yes, some of these replacements are... questionable. But I wanted to try and maximise the replacement for now. * Bump kotlinx-datetime to 0.8.0 * More kotlin.time/kotlinx-datetime replacements * Remove redundant init block & make attributes val * Replace new use of java.time.Instant
This commit is contained in:
@@ -18,7 +18,7 @@ import tachiyomi.core.common.storage.displayablePath
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
class BackupNotifier(private val context: Context) {
|
||||
|
||||
@@ -149,10 +149,8 @@ class BackupNotifier(private val context: Context) {
|
||||
|
||||
val timeString = context.stringResource(
|
||||
MR.strings.restore_duration,
|
||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
||||
TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds(
|
||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
||||
),
|
||||
time.milliseconds.inWholeMinutes,
|
||||
time.milliseconds.inWholeSeconds - (time.milliseconds.inWholeMinutes * 60),
|
||||
)
|
||||
|
||||
with(completeNotificationBuilder) {
|
||||
|
||||
@@ -33,9 +33,9 @@ import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.FileOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.Instant
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlin.time.Clock
|
||||
|
||||
class BackupCreator(
|
||||
private val context: Context,
|
||||
@@ -108,7 +108,7 @@ class BackupCreator(
|
||||
BackupFileValidator(context).validate(fileUri)
|
||||
|
||||
if (isAutoBackup) {
|
||||
backupPreferences.lastAutoBackupTimestamp.set(Instant.now().toEpochMilli())
|
||||
backupPreferences.lastAutoBackupTimestamp.set(Clock.System.now().toEpochMilliseconds())
|
||||
}
|
||||
|
||||
return fileUri.toString()
|
||||
|
||||
+7
-9
@@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupTracking
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import tachiyomi.data.Database
|
||||
import tachiyomi.data.MemoColumnAdapter
|
||||
import tachiyomi.data.UpdateStrategyColumnAdapter
|
||||
@@ -23,9 +25,9 @@ import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.domain.track.model.Track
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.ZonedDateTime
|
||||
import java.util.Date
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Clock
|
||||
|
||||
class MangaRestorer(
|
||||
private val database: Database = Injekt.get(),
|
||||
@@ -38,13 +40,9 @@ class MangaRestorer(
|
||||
fetchInterval: FetchInterval = Injekt.get(),
|
||||
) {
|
||||
|
||||
private var now = ZonedDateTime.now()
|
||||
private var currentFetchWindow = fetchInterval.getWindow(now)
|
||||
|
||||
init {
|
||||
now = ZonedDateTime.now()
|
||||
currentFetchWindow = fetchInterval.getWindow(now)
|
||||
}
|
||||
private val timeZone = TimeZone.currentSystemDefault()
|
||||
private val now = Clock.System.now().toLocalDateTime(timeZone)
|
||||
private val currentFetchWindow = fetchInterval.getWindow(now.date, timeZone)
|
||||
|
||||
suspend fun sortByNew(backupMangas: List<BackupManga>): List<BackupManga> {
|
||||
val urlsBySource = database.mangasQueries
|
||||
@@ -286,7 +284,7 @@ class MangaRestorer(
|
||||
restoreTracking(manga, tracks)
|
||||
restoreHistory(manga, history)
|
||||
restoreExcludedScanlators(manga, excludedScanlators)
|
||||
updateManga.awaitUpdateFetchInterval(manga, now, currentFetchWindow)
|
||||
updateManga.awaitUpdateFetchInterval(manga, timeZone, now, currentFetchWindow)
|
||||
return manga
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import logcat.LogPriority
|
||||
import mihon.domain.chapter.interactor.FilterChaptersForDownload
|
||||
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
||||
@@ -64,14 +66,13 @@ import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.time.Instant
|
||||
import java.time.ZonedDateTime
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.concurrent.atomics.AtomicBoolean
|
||||
import kotlin.concurrent.atomics.AtomicInt
|
||||
import kotlin.concurrent.atomics.ExperimentalAtomicApi
|
||||
import kotlin.concurrent.atomics.incrementAndFetch
|
||||
import kotlin.time.Clock
|
||||
|
||||
@OptIn(ExperimentalAtomicApi::class)
|
||||
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
@@ -108,7 +109,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
|
||||
setForegroundSafely()
|
||||
|
||||
libraryPreferences.lastUpdatedTimestamp.set(Instant.now().toEpochMilli())
|
||||
libraryPreferences.lastUpdatedTimestamp.set(Clock.System.now().toEpochMilliseconds())
|
||||
|
||||
val categoryId = inputData.getLong(KEY_CATEGORY, -1L)
|
||||
addMangaToQueue(categoryId)
|
||||
@@ -167,7 +168,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
|
||||
val restrictions = libraryPreferences.autoUpdateMangaRestrictions.get()
|
||||
val skippedUpdates = mutableListOf<Pair<Manga, String?>>()
|
||||
val (_, fetchWindowUpperBound) = fetchInterval.getWindow(ZonedDateTime.now())
|
||||
val timeZone = TimeZone.currentSystemDefault()
|
||||
val (_, fetchWindowUpperBound) = fetchInterval.getWindow(
|
||||
Clock.System.now().toLocalDateTime(timeZone).date,
|
||||
timeZone,
|
||||
)
|
||||
|
||||
mangaToUpdate = listToUpdate
|
||||
.filter {
|
||||
@@ -234,7 +239,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<Chapter>>>()
|
||||
val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
|
||||
val hasDownloads = AtomicBoolean(false)
|
||||
val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
|
||||
val timeZone = TimeZone.currentSystemDefault()
|
||||
val fetchWindow = fetchInterval.getWindow(Clock.System.now().toLocalDateTime(timeZone).date, timeZone)
|
||||
|
||||
coroutineScope {
|
||||
mangaToUpdate.groupBy { it.manga.source }.values
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.time.Instant
|
||||
import kotlin.time.Clock
|
||||
|
||||
class ImageSaver(
|
||||
val context: Context,
|
||||
@@ -85,7 +85,7 @@ class ImageSaver(
|
||||
MediaStore.MediaColumns.RELATIVE_PATH to relativePath,
|
||||
MediaStore.MediaColumns.DISPLAY_NAME to if (isMimeTypeSupported) image.name else filename,
|
||||
MediaStore.MediaColumns.MIME_TYPE to type.mime,
|
||||
MediaStore.MediaColumns.DATE_MODIFIED to Instant.now().epochSecond,
|
||||
MediaStore.MediaColumns.DATE_MODIFIED to Clock.System.now().epochSeconds,
|
||||
)
|
||||
|
||||
val picture = findUriOrDefault(relativePath, filename) {
|
||||
|
||||
@@ -15,6 +15,9 @@ import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.network.jsonMime
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.number
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
@@ -25,10 +28,8 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Instant
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
@@ -326,11 +327,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
}
|
||||
|
||||
val dateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(dateValue), ZoneId.systemDefault())
|
||||
val dateTime = Instant.fromEpochMilliseconds(dateValue).toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
return buildJsonObject {
|
||||
put("year", dateTime.year)
|
||||
put("month", dateTime.monthValue)
|
||||
put("day", dateTime.dayOfMonth)
|
||||
put("month", dateTime.month.number)
|
||||
put("day", dateTime.day)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package eu.kanade.tachiyomi.data.track.anilist.dto
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.atStartOfDayIn
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
|
||||
@Serializable
|
||||
data class ALFuzzyDate(
|
||||
@@ -11,10 +12,9 @@ data class ALFuzzyDate(
|
||||
val day: Int?,
|
||||
) {
|
||||
fun toEpochMilli(): Long = try {
|
||||
LocalDate.of(year!!, month!!, day!!)
|
||||
.atStartOfDay(ZoneId.systemDefault())
|
||||
.toInstant()
|
||||
.toEpochMilli()
|
||||
LocalDate(year!!, month!!, day!!)
|
||||
.atStartOfDayIn(TimeZone.currentSystemDefault())
|
||||
.toEpochMilliseconds()
|
||||
} catch (_: Exception) {
|
||||
0L
|
||||
}
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ import tachiyomi.domain.source.interactor.GetRemoteManga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
import kotlin.time.Clock
|
||||
import eu.kanade.tachiyomi.source.model.Filter as SourceModelFilter
|
||||
|
||||
class BrowseSourceViewModel(
|
||||
@@ -226,7 +226,7 @@ class BrowseSourceViewModel(
|
||||
favorite = !manga.favorite,
|
||||
dateAdded = when (manga.favorite) {
|
||||
true -> 0
|
||||
false -> Instant.now().toEpochMilli()
|
||||
false -> Clock.System.now().toEpochMilliseconds()
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
|
||||
import eu.kanade.tachiyomi.util.lang.toLocalDate
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
@@ -66,6 +65,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import logcat.LogPriority
|
||||
import mihon.core.viewmodel.StateViewModel
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
@@ -85,9 +86,8 @@ import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneOffset
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
data class TrackInfoDialogHomeScreen(
|
||||
private val mangaId: Long,
|
||||
@@ -513,20 +513,20 @@ private data class TrackDateSelectorScreen(
|
||||
@Transient
|
||||
private val selectableDates = object : SelectableDates {
|
||||
override fun isSelectableDate(utcTimeMillis: Long): Boolean {
|
||||
val targetDate = Instant.ofEpochMilli(utcTimeMillis).toLocalDate(ZoneOffset.UTC)
|
||||
val targetDate = Instant.fromEpochMilliseconds(utcTimeMillis).toLocalDateTime(TimeZone.UTC)
|
||||
|
||||
// Disallow future dates
|
||||
if (targetDate > LocalDate.now(ZoneOffset.UTC)) return false
|
||||
if (targetDate > Clock.System.now().toLocalDateTime(TimeZone.UTC)) return false
|
||||
|
||||
return when {
|
||||
// Disallow setting start date after finish date
|
||||
start && track.finishDate > 0 -> {
|
||||
val finishDate = Instant.ofEpochMilli(track.finishDate).toLocalDate(ZoneOffset.UTC)
|
||||
val finishDate = Instant.fromEpochMilliseconds(track.finishDate).toLocalDateTime(TimeZone.UTC)
|
||||
targetDate <= finishDate
|
||||
}
|
||||
// Disallow setting finish date before start date
|
||||
!start && track.startDate > 0 -> {
|
||||
val startDate = Instant.ofEpochMilli(track.startDate).toLocalDate(ZoneOffset.UTC)
|
||||
val startDate = Instant.fromEpochMilliseconds(track.startDate).toLocalDateTime(TimeZone.UTC)
|
||||
startDate <= targetDate
|
||||
}
|
||||
else -> {
|
||||
@@ -537,17 +537,17 @@ private data class TrackDateSelectorScreen(
|
||||
|
||||
override fun isSelectableYear(year: Int): Boolean {
|
||||
// Disallow future years
|
||||
if (year > LocalDate.now(ZoneOffset.UTC).year) return false
|
||||
if (year > Clock.System.now().toLocalDateTime(TimeZone.UTC).year) return false
|
||||
|
||||
return when {
|
||||
// Disallow setting start year after finish year
|
||||
start && track.finishDate > 0 -> {
|
||||
val finishDate = Instant.ofEpochMilli(track.finishDate).toLocalDate(ZoneOffset.UTC)
|
||||
val finishDate = Instant.fromEpochMilliseconds(track.finishDate).toLocalDateTime(TimeZone.UTC)
|
||||
year <= finishDate.year
|
||||
}
|
||||
// Disallow setting finish year before start year
|
||||
!start && track.startDate > 0 -> {
|
||||
val startDate = Instant.ofEpochMilli(track.startDate).toLocalDate(ZoneOffset.UTC)
|
||||
val startDate = Instant.fromEpochMilliseconds(track.startDate).toLocalDateTime(TimeZone.UTC)
|
||||
startDate.year <= year
|
||||
}
|
||||
else -> {
|
||||
@@ -618,14 +618,14 @@ private data class TrackDateSelectorScreen(
|
||||
get() {
|
||||
val millis = (if (start) track.startDate else track.finishDate)
|
||||
.takeIf { it != 0L }
|
||||
?: Instant.now().toEpochMilli()
|
||||
return millis.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC)
|
||||
?: Clock.System.now().toEpochMilliseconds()
|
||||
return millis.convertEpochMillisZone(TimeZone.currentSystemDefault(), TimeZone.UTC)
|
||||
}
|
||||
|
||||
// In UTC
|
||||
fun setDate(millis: Long) {
|
||||
// Convert to local time
|
||||
val localMillis = millis.convertEpochMillisZone(ZoneOffset.UTC, ZoneOffset.systemDefault())
|
||||
val localMillis = millis.convertEpochMillisZone(TimeZone.UTC, TimeZone.currentSystemDefault())
|
||||
viewModelScope.launchNonCancellable {
|
||||
if (start) {
|
||||
tracker.setRemoteStartDate(track.toDbTrack(), localMillis)
|
||||
|
||||
@@ -76,8 +76,9 @@ import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
import java.util.Date
|
||||
import kotlin.getValue
|
||||
import kotlin.time.Clock
|
||||
|
||||
/**
|
||||
* Presenter used by the activity to perform background operations.
|
||||
@@ -582,7 +583,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun restartReadTimer() {
|
||||
chapterReadStartTime = Instant.now().toEpochMilli()
|
||||
chapterReadStartTime = Clock.System.now().toEpochMilliseconds()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,9 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.DateTimeUnit
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.minus
|
||||
import logcat.LogPriority
|
||||
import mihon.core.viewmodel.StateViewModel
|
||||
import tachiyomi.core.common.preference.TriState
|
||||
@@ -49,7 +52,7 @@ import tachiyomi.domain.updates.model.UpdatesWithRelations
|
||||
import tachiyomi.domain.updates.service.UpdatesPreferences
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.ZonedDateTime
|
||||
import kotlin.time.Clock
|
||||
|
||||
class UpdatesViewModel(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
@@ -77,7 +80,7 @@ class UpdatesViewModel(
|
||||
init {
|
||||
viewModelScope.launchIO {
|
||||
// Set date limit for recent chapters
|
||||
val limit = ZonedDateTime.now().minusMonths(3).toInstant()
|
||||
val limit = Clock.System.now().minus(3, DateTimeUnit.MONTH, TimeZone.currentSystemDefault())
|
||||
|
||||
combine(
|
||||
// needed for SQL filters (unread, started, bookmarked, etc)
|
||||
|
||||
@@ -10,12 +10,14 @@ import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.offsetAt
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneId
|
||||
import kotlin.time.Clock
|
||||
|
||||
class CrashLogUtil(
|
||||
private val context: Context,
|
||||
@@ -35,12 +37,14 @@ class CrashLogUtil(
|
||||
|
||||
val uri = file.getUriCompat(context)
|
||||
context.startActivity(uri.toShareIntent(context, "text/plain"))
|
||||
} catch (e: Throwable) {
|
||||
} catch (_: Throwable) {
|
||||
withUIContext { context.toast("Failed to get logs") }
|
||||
}
|
||||
}
|
||||
|
||||
fun getDebugInfo(): String {
|
||||
val now = Clock.System.now()
|
||||
val tz = TimeZone.currentSystemDefault()
|
||||
return """
|
||||
App ID: ${BuildConfig.APPLICATION_ID}
|
||||
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME})
|
||||
@@ -51,7 +55,7 @@ class CrashLogUtil(
|
||||
Device name: ${Build.DEVICE} (${Build.PRODUCT})
|
||||
Device model: ${Build.MODEL}
|
||||
WebView: ${WebViewUtil.getVersion(context)}
|
||||
Current time: ${OffsetDateTime.now(ZoneId.systemDefault())}
|
||||
Current time: ${now.toLocalDateTime(tz)}${tz.offsetAt(now)}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.InputStream
|
||||
import java.time.Instant
|
||||
import kotlin.time.Clock
|
||||
|
||||
fun Manga.removeCovers(coverCache: CoverCache = Injekt.get()): Manga {
|
||||
if (isLocal()) return this
|
||||
return if (coverCache.deleteFromCache(this, true) > 0) {
|
||||
copy(coverLastModified = Instant.now().toEpochMilli())
|
||||
copy(coverLastModified = Clock.System.now().toEpochMilliseconds())
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
package eu.kanade.tachiyomi.util.lang
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.minus
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toJavaLocalDate
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import tachiyomi.core.common.i18n.pluralStringResource
|
||||
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.Date
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
fun LocalDateTime.toDateTimestampString(dateTimeFormatter: DateTimeFormatter): String {
|
||||
val date = dateTimeFormatter.format(this)
|
||||
val time = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(this)
|
||||
val javaLocalDateTime = this.toJavaLocalDateTime()
|
||||
val date = dateTimeFormatter.format(javaLocalDateTime)
|
||||
val time = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(javaLocalDateTime)
|
||||
return "$date $time"
|
||||
}
|
||||
|
||||
@@ -26,21 +32,21 @@ fun Date.toTimestampString(): String {
|
||||
}
|
||||
|
||||
fun Long.convertEpochMillisZone(
|
||||
from: ZoneId,
|
||||
to: ZoneId,
|
||||
from: TimeZone,
|
||||
to: TimeZone,
|
||||
): Long {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(this), from)
|
||||
.atZone(to)
|
||||
.toInstant()
|
||||
.toEpochMilli()
|
||||
return Instant.fromEpochMilliseconds(this)
|
||||
.toLocalDateTime(from)
|
||||
.toInstant(to)
|
||||
.toEpochMilliseconds()
|
||||
}
|
||||
|
||||
fun Long.toLocalDate(): LocalDate {
|
||||
return LocalDate.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
|
||||
return Instant.fromEpochMilliseconds(this).toLocalDateTime(TimeZone.currentSystemDefault()).date
|
||||
}
|
||||
|
||||
fun Instant.toLocalDate(zoneId: ZoneId = ZoneId.systemDefault()): LocalDate {
|
||||
return LocalDate.ofInstant(this, zoneId)
|
||||
fun Long.toJavaLocalDate(): java.time.LocalDate {
|
||||
return this.toLocalDate().toJavaLocalDate()
|
||||
}
|
||||
|
||||
fun LocalDate.toRelativeString(
|
||||
@@ -49,23 +55,25 @@ fun LocalDate.toRelativeString(
|
||||
dateFormat: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT),
|
||||
): String {
|
||||
if (!relative) {
|
||||
return dateFormat.format(this)
|
||||
return dateFormat.format(this.toJavaLocalDate())
|
||||
}
|
||||
val now = LocalDate.now()
|
||||
val difference = ChronoUnit.DAYS.between(this, now)
|
||||
val today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
|
||||
val difference = (today - this).days
|
||||
return when {
|
||||
difference < -7 -> dateFormat.format(this)
|
||||
difference < -7 -> dateFormat.format(this.toJavaLocalDate())
|
||||
difference < 0 -> context.pluralStringResource(
|
||||
MR.plurals.upcoming_relative_time,
|
||||
difference.toInt().absoluteValue,
|
||||
difference.toInt().absoluteValue,
|
||||
difference.absoluteValue,
|
||||
difference.absoluteValue,
|
||||
)
|
||||
|
||||
difference < 1 -> context.stringResource(MR.strings.relative_time_today)
|
||||
difference < 7 -> context.pluralStringResource(
|
||||
MR.plurals.relative_time,
|
||||
difference.toInt(),
|
||||
difference.toInt(),
|
||||
difference,
|
||||
difference,
|
||||
)
|
||||
else -> dateFormat.format(this)
|
||||
|
||||
else -> dateFormat.format(this.toJavaLocalDate())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user