From c8dda45d1553d747abefe8ce6aef91f5f60ed8e7 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Sat, 12 Aug 2023 09:10:19 +0530 Subject: [PATCH 1/2] Switch to java.time --- app/build.gradle | 6 +-- .../kotatsu/bookmarks/data/EntityMapping.kt | 6 +-- .../kotatsu/bookmarks/domain/Bookmark.kt | 4 +- .../kotatsu/core/backup/BackupZipOutput.kt | 6 +-- .../exceptions/TooManyRequestExceptions.kt | 8 +-- .../koitharu/kotatsu/core/logs/FileLogger.kt | 13 ++--- .../kotatsu/core/model/FavouriteCategory.kt | 4 +- .../kotatsu/core/model/MangaHistory.kt | 8 +-- .../core/network/RateLimitInterceptor.kt | 18 +++---- .../kotatsu/core/ui/model/DateTimeAgo.kt | 29 +++-------- .../kotatsu/core/util/AcraScreenLogger.kt | 12 ++--- .../koitharu/kotatsu/core/util/ext/Date.kt | 50 +++++++++---------- .../kotatsu/download/domain/DownloadState.kt | 4 +- .../download/ui/list/DownloadItemModel.kt | 4 +- .../download/ui/list/DownloadsViewModel.kt | 19 +------ .../kotatsu/favourites/data/EntityMapping.kt | 4 +- .../kotatsu/history/data/EntityMapping.kt | 8 +-- .../history/ui/HistoryListMenuProvider.kt | 13 ++--- .../history/ui/HistoryListViewModel.kt | 30 +++-------- .../kotatsu/reader/ui/ReaderInfoBarView.kt | 11 ++-- .../kotatsu/reader/ui/ReaderViewModel.kt | 4 +- .../kotatsu/tracker/data/EntityMapping.kt | 4 +- .../tracker/domain/TrackingRepository.kt | 6 +-- .../tracker/domain/model/MangaTracking.kt | 4 +- .../tracker/domain/model/TrackingLogItem.kt | 4 +- .../kotatsu/tracker/ui/feed/FeedViewModel.kt | 19 +------ 26 files changed, 114 insertions(+), 184 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dee9651f9..1e66f7fee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,11 +48,11 @@ android { } compileOptions { coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + jvmTarget = JavaVersion.VERSION_17 freeCompilerArgs += [ '-opt-in=kotlin.ExperimentalStdlibApi', '-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi', diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/EntityMapping.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/EntityMapping.kt index 37816464e..20dd8a77a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/EntityMapping.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/data/EntityMapping.kt @@ -2,7 +2,7 @@ package org.koitharu.kotatsu.bookmarks.data import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.parsers.model.Manga -import java.util.Date +import java.time.Instant fun BookmarkEntity.toBookmark(manga: Manga) = Bookmark( manga = manga, @@ -11,7 +11,7 @@ fun BookmarkEntity.toBookmark(manga: Manga) = Bookmark( page = page, scroll = scroll, imageUrl = imageUrl, - createdAt = Date(createdAt), + createdAt = Instant.ofEpochMilli(createdAt), percent = percent, ) @@ -22,7 +22,7 @@ fun Bookmark.toEntity() = BookmarkEntity( page = page, scroll = scroll, imageUrl = imageUrl, - createdAt = createdAt.time, + createdAt = createdAt.toEpochMilli(), percent = percent, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt index f9b74f99f..ad092b746 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/domain/Bookmark.kt @@ -4,7 +4,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.local.data.hasImageExtension import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaPage -import java.util.Date +import java.time.Instant data class Bookmark( val manga: Manga, @@ -13,7 +13,7 @@ data class Bookmark( val page: Int, val scroll: Int, val imageUrl: String, - val createdAt: Date, + val createdAt: Instant, val percent: Float, ) : ListModel { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipOutput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipOutput.kt index 199a751ae..c246818de 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipOutput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipOutput.kt @@ -5,10 +5,10 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible import okio.Closeable import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.util.ext.format import org.koitharu.kotatsu.core.zip.ZipOutput import java.io.File -import java.util.Date +import java.time.LocalDate +import java.time.format.DateTimeFormatter import java.util.Locale import java.util.zip.Deflater @@ -39,7 +39,7 @@ suspend fun BackupZipOutput(context: Context): BackupZipOutput = runInterruptibl val filename = buildString { append(context.getString(R.string.app_name).replace(' ', '_').lowercase(Locale.ROOT)) append('_') - append(Date().format("ddMMyyyy")) + append(LocalDate.now().format(DateTimeFormatter.ofPattern("ddMMyyyy"))) append(".bk.zip") } BackupZipOutput(File(dir, filename)) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/TooManyRequestExceptions.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/TooManyRequestExceptions.kt index 17bea32f1..6e99991f6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/TooManyRequestExceptions.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/TooManyRequestExceptions.kt @@ -1,13 +1,13 @@ package org.koitharu.kotatsu.core.exceptions import okio.IOException -import java.util.Date +import java.time.Instant +import java.time.temporal.ChronoUnit class TooManyRequestExceptions( val url: String, - val retryAt: Date?, + val retryAt: Instant?, ) : IOException() { - val retryAfter: Long - get() = if (retryAt == null) 0 else (retryAt.time - System.currentTimeMillis()).coerceAtLeast(0) + get() = retryAt?.until(Instant.now(), ChronoUnit.MILLIS) ?: 0 } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/logs/FileLogger.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/logs/FileLogger.kt index ee75e9e21..60a1e1d83 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/logs/FileLogger.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/logs/FileLogger.kt @@ -20,8 +20,9 @@ import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import java.io.File import java.io.FileOutputStream -import java.text.SimpleDateFormat -import java.util.Date +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle import java.util.Locale import java.util.concurrent.ConcurrentLinkedQueue @@ -41,11 +42,7 @@ class FileLogger( } val isEnabled: Boolean get() = settings.isLoggingEnabled - private val dateFormat = SimpleDateFormat.getDateTimeInstance( - SimpleDateFormat.SHORT, - SimpleDateFormat.SHORT, - Locale.ROOT, - ) + private val dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.ROOT) private val buffer = ConcurrentLinkedQueue() private val mutex = Mutex() private var flushJob: Job? = null @@ -55,7 +52,7 @@ class FileLogger( return } val text = buildString { - append(dateFormat.format(Date())) + append(dateTimeFormatter.format(LocalDateTime.now())) append(": ") if (e != null) { append("E!") diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/FavouriteCategory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/FavouriteCategory.kt index 1a0ed5b23..017f1b73e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/FavouriteCategory.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/FavouriteCategory.kt @@ -5,7 +5,7 @@ import kotlinx.parcelize.Parcelize import org.koitharu.kotatsu.list.domain.ListSortOrder import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel -import java.util.Date +import java.time.Instant @Parcelize data class FavouriteCategory( @@ -13,7 +13,7 @@ data class FavouriteCategory( val title: String, val sortKey: Int, val order: ListSortOrder, - val createdAt: Date, + val createdAt: Instant, val isTrackingEnabled: Boolean, val isVisibleInLibrary: Boolean, ) : Parcelable, ListModel { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaHistory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaHistory.kt index 9ac085183..d72ed9d3a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaHistory.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaHistory.kt @@ -2,14 +2,14 @@ package org.koitharu.kotatsu.core.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -import java.util.* +import java.time.Instant @Parcelize data class MangaHistory( - val createdAt: Date, - val updatedAt: Date, + val createdAt: Instant, + val updatedAt: Instant, val chapterId: Long, val page: Int, val scroll: Int, val percent: Float, -) : Parcelable \ No newline at end of file +) : Parcelable diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/RateLimitInterceptor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/RateLimitInterceptor.kt index 83e3dbb6e..3b3168d47 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/RateLimitInterceptor.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/RateLimitInterceptor.kt @@ -4,15 +4,11 @@ import okhttp3.Interceptor import okhttp3.Response import okhttp3.internal.closeQuietly import org.koitharu.kotatsu.core.exceptions.TooManyRequestExceptions -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.concurrent.TimeUnit +import java.time.Instant +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter class RateLimitInterceptor : Interceptor { - - private val dateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ZZZ", Locale.ENGLISH) - override fun intercept(chain: Interceptor.Chain): Response { val response = chain.proceed(chain.request()) if (response.code == 429) { @@ -27,10 +23,8 @@ class RateLimitInterceptor : Interceptor { return response } - private fun String.parseRetryDate(): Date? { - toIntOrNull()?.let { - return Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(it.toLong())) - } - return dateFormat.parse(this) + private fun String.parseRetryDate(): Instant? { + return toLongOrNull()?.let { Instant.now().plusSeconds(it) } + ?: ZonedDateTime.parse(this, DateTimeFormatter.RFC_1123_DATE_TIME).toInstant() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt index 87720d0c6..cbee580f3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt @@ -2,9 +2,8 @@ package org.koitharu.kotatsu.core.ui.model import android.content.res.Resources import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.util.ext.daysDiff -import org.koitharu.kotatsu.core.util.ext.format -import java.util.Date +import java.time.LocalDate +import java.time.format.DateTimeFormatter sealed class DateTimeAgo { @@ -74,32 +73,20 @@ sealed class DateTimeAgo { } } - class Absolute(private val date: Date) : DateTimeAgo() { - - private val day = date.daysDiff(0) - + data class Absolute(private val date: LocalDate) : DateTimeAgo() { override fun format(resources: Resources): String { - return if (date.time == 0L) { + return if (date == LocalDate.EPOCH) { resources.getString(R.string.unknown) } else { - date.format("d MMMM") + date.format(formatter) } } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Absolute + override fun toString() = "abs_${date.toEpochDay()}" - return day == other.day + companion object { + private val formatter = DateTimeFormatter.ofPattern("d MMMM") } - - override fun hashCode(): Int { - return day - } - - override fun toString() = "abs_$day" } object LongAgo : DateTimeAgo() { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/AcraScreenLogger.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/AcraScreenLogger.kt index 104446a3f..5926cd7a1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/AcraScreenLogger.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/AcraScreenLogger.kt @@ -9,10 +9,8 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks import org.acra.ACRA import org.koitharu.kotatsu.core.ui.DefaultActivityLifecycleCallbacks -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale +import java.time.LocalTime +import java.time.temporal.ChronoUnit import java.util.WeakHashMap import javax.inject.Inject import javax.inject.Singleton @@ -20,7 +18,6 @@ import javax.inject.Singleton @Singleton class AcraScreenLogger @Inject constructor() : FragmentLifecycleCallbacks(), DefaultActivityLifecycleCallbacks { - private val timeFormat = SimpleDateFormat.getTimeInstance(DateFormat.DEFAULT, Locale.ROOT) private val keys = WeakHashMap() override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) { @@ -47,11 +44,10 @@ class AcraScreenLogger @Inject constructor() : FragmentLifecycleCallbacks(), Def } private fun Any.key() = keys.getOrPut(this) { - "${time()}: ${javaClass.simpleName}" + val time = LocalTime.now().truncatedTo(ChronoUnit.SECONDS) + "$time: ${javaClass.simpleName}" } - private fun time() = timeFormat.format(Date()) - @Suppress("DEPRECATION") private fun Bundle?.contentToString() = this?.keySet()?.joinToString { k -> val v = get(k) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt index e75842410..b738cbac0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt @@ -1,30 +1,30 @@ package org.koitharu.kotatsu.core.util.ext -import android.annotation.SuppressLint -import android.text.format.DateUtils -import java.text.SimpleDateFormat -import java.util.* -import java.util.concurrent.TimeUnit +import org.koitharu.kotatsu.core.ui.model.DateTimeAgo +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId +import java.time.temporal.ChronoUnit -@SuppressLint("SimpleDateFormat") -fun Date.format(pattern: String): String = SimpleDateFormat(pattern).format(this) +fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo { + val localDate = LocalDate.ofInstant(instant, ZoneId.systemDefault()) + val now = LocalDate.now() + val diffDays = localDate.until(now, ChronoUnit.DAYS) -fun Date.formatRelative(minResolution: Long): CharSequence = DateUtils.getRelativeTimeSpanString( - time, System.currentTimeMillis(), minResolution, -) - -fun Date.daysDiff(other: Long): Int { - val thisDay = time / TimeUnit.DAYS.toMillis(1L) - val otherDay = other / TimeUnit.DAYS.toMillis(1L) - return (thisDay - otherDay).toInt() -} - -fun Date.startOfDay(): Long { - val calendar = Calendar.getInstance() - calendar.time = this - calendar[Calendar.HOUR_OF_DAY] = 0 - calendar[Calendar.MINUTE] = 0 - calendar[Calendar.SECOND] = 0 - calendar[Calendar.MILLISECOND] = 0 - return calendar.timeInMillis + return when { + diffDays == 0L -> { + if (instant.until(Instant.now(), ChronoUnit.MINUTES) < 3) DateTimeAgo.JustNow + else DateTimeAgo.Today + } + diffDays == 1L -> DateTimeAgo.Yesterday + diffDays < 6 -> DateTimeAgo.DaysAgo(diffDays.toInt()) + else -> { + val diffMonths = localDate.until(now, ChronoUnit.MONTHS) + if (showMonths && diffMonths <= 6) { + DateTimeAgo.MonthsAgo(diffMonths.toInt()) + } else { + DateTimeAgo.Absolute(localDate) + } + } + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt index d7ba74fc3..6f392ee50 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/domain/DownloadState.kt @@ -4,7 +4,7 @@ import androidx.work.Data import org.koitharu.kotatsu.history.data.PROGRESS_NONE import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga -import java.util.Date +import java.time.Instant data class DownloadState( val manga: Manga, @@ -72,7 +72,7 @@ data class DownloadState( fun getEta(data: Data): Long = data.getLong(DATA_ETA, -1L) - fun getTimestamp(data: Data): Date = Date(data.getLong(DATA_TIMESTAMP, 0L)) + fun getTimestamp(data: Data): Instant = Instant.ofEpochMilli(data.getLong(DATA_TIMESTAMP, 0L)) fun getDownloadedChapters(data: Data): Int = data.getInt(DATA_CHAPTERS, 0) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemModel.kt index 5a19a7aa4..2cd973695 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadItemModel.kt @@ -8,7 +8,7 @@ import org.koitharu.kotatsu.download.ui.list.chapters.DownloadChapter import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.parsers.model.Manga -import java.util.Date +import java.time.Instant import java.util.UUID data class DownloadItemModel( @@ -21,7 +21,7 @@ data class DownloadItemModel( val max: Int, val progress: Int, val eta: Long, - val timestamp: Date, + val timestamp: Instant, val chaptersDownloaded: Int, val isExpanded: Boolean, val chapters: StateFlow?>, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt index 559723c4e..96a884748 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsViewModel.kt @@ -28,8 +28,8 @@ import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.util.ext.MutableEventFlow +import org.koitharu.kotatsu.core.util.ext.calculateTimeAgo import org.koitharu.kotatsu.core.util.ext.call -import org.koitharu.kotatsu.core.util.ext.daysDiff import org.koitharu.kotatsu.core.util.ext.isEmpty import org.koitharu.kotatsu.download.domain.DownloadState import org.koitharu.kotatsu.download.ui.list.chapters.DownloadChapter @@ -44,10 +44,8 @@ import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import java.util.Date import java.util.LinkedList import java.util.UUID -import java.util.concurrent.TimeUnit import javax.inject.Inject @HiltViewModel @@ -225,7 +223,7 @@ class DownloadsViewModel @Inject constructor( WorkInfo.State.ENQUEUED -> queued += item else -> { - val date = timeAgo(item.timestamp) + val date = calculateTimeAgo(item.timestamp) if (prevDate != date) { destination += ListHeader(date) } @@ -275,19 +273,6 @@ class DownloadsViewModel @Inject constructor( ) } - private fun timeAgo(date: Date): DateTimeAgo { - val diff = (System.currentTimeMillis() - date.time).coerceAtLeast(0L) - val diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diff).toInt() - val diffDays = -date.daysDiff(System.currentTimeMillis()) - return when { - diffMinutes < 3 -> DateTimeAgo.JustNow - diffDays < 1 -> DateTimeAgo.Today - diffDays == 1 -> DateTimeAgo.Yesterday - diffDays < 6 -> DateTimeAgo.DaysAgo(diffDays) - else -> DateTimeAgo.Absolute(date) - } - } - private fun emptyStateList() = listOf( EmptyState( icon = R.drawable.ic_empty_common, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/data/EntityMapping.kt b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/data/EntityMapping.kt index df2320a87..a99afe241 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/favourites/data/EntityMapping.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/favourites/data/EntityMapping.kt @@ -4,14 +4,14 @@ import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.list.domain.ListSortOrder -import java.util.Date +import java.time.Instant fun FavouriteCategoryEntity.toFavouriteCategory(id: Long = categoryId.toLong()) = FavouriteCategory( id = id, title = title, sortKey = sortKey, order = ListSortOrder(order, ListSortOrder.NEWEST), - createdAt = Date(createdAt), + createdAt = Instant.ofEpochMilli(createdAt), isTrackingEnabled = track, isVisibleInLibrary = isVisibleInLibrary, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/EntityMapping.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/EntityMapping.kt index 0e5624559..664fbbc0d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/EntityMapping.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/EntityMapping.kt @@ -1,13 +1,13 @@ package org.koitharu.kotatsu.history.data import org.koitharu.kotatsu.core.model.MangaHistory -import java.util.* +import java.time.Instant fun HistoryEntity.toMangaHistory() = MangaHistory( - createdAt = Date(createdAt), - updatedAt = Date(updatedAt), + createdAt = Instant.ofEpochMilli(createdAt), + updatedAt = Instant.ofEpochMilli(updatedAt), chapterId = chapterId, page = page, scroll = scroll.toInt(), percent = percent, -) \ No newline at end of file +) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt index ddd41df4a..08b1f82f4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListMenuProvider.kt @@ -8,9 +8,10 @@ import androidx.core.view.MenuProvider import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.dialog.RememberSelectionDialogListener -import org.koitharu.kotatsu.core.util.ext.startOfDay -import java.util.Date -import java.util.concurrent.TimeUnit +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId +import java.time.temporal.ChronoUnit import com.google.android.material.R as materialR class HistoryListMenuProvider( @@ -50,9 +51,9 @@ class HistoryListMenuProvider( .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.clear) { _, _ -> val minDate = when (selectionListener.selection) { - 0 -> System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2) - 1 -> Date().startOfDay() - 2 -> 0L + 0 -> Instant.now().minus(2, ChronoUnit.HOURS) + 1 -> LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant() + 2 -> Instant.EPOCH else -> return@setPositiveButton } viewModel.clearHistory(minDate) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt index a263b7038..a9efc440f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/ui/HistoryListViewModel.kt @@ -19,10 +19,9 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.prefs.observeAsStateFlow -import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.ui.util.ReversibleAction +import org.koitharu.kotatsu.core.util.ext.calculateTimeAgo import org.koitharu.kotatsu.core.util.ext.call -import org.koitharu.kotatsu.core.util.ext.daysDiff import org.koitharu.kotatsu.core.util.ext.onFirst import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.history.data.HistoryRepository @@ -40,8 +39,7 @@ import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.list.ui.model.toListDetailedModel import org.koitharu.kotatsu.list.ui.model.toListModel import org.koitharu.kotatsu.local.data.LocalMangaRepository -import java.util.Date -import java.util.concurrent.TimeUnit +import java.time.Instant import javax.inject.Inject @HiltViewModel @@ -100,13 +98,13 @@ class HistoryListViewModel @Inject constructor( override fun onRetry() = Unit - fun clearHistory(minDate: Long) { + fun clearHistory(minDate: Instant) { launchJob(Dispatchers.Default) { - val stringRes = if (minDate <= 0) { + val stringRes = if (minDate <= Instant.EPOCH) { repository.clear() R.string.history_cleared } else { - repository.deleteAfter(minDate) + repository.deleteAfter(minDate.toEpochMilli()) R.string.removed_from_history } onActionDone.call(ReversibleAction(stringRes, null)) @@ -165,8 +163,8 @@ class HistoryListViewModel @Inject constructor( } private fun MangaHistory.header(order: ListSortOrder): ListHeader? = when (order) { - ListSortOrder.UPDATED -> ListHeader(timeAgo(updatedAt)) - ListSortOrder.NEWEST -> ListHeader(timeAgo(createdAt)) + ListSortOrder.UPDATED -> ListHeader(calculateTimeAgo(updatedAt)) + ListSortOrder.NEWEST -> ListHeader(calculateTimeAgo(createdAt)) ListSortOrder.PROGRESS -> ListHeader( when (percent) { 1f -> R.string.status_completed @@ -181,18 +179,4 @@ class HistoryListViewModel @Inject constructor( ListSortOrder.NEW_CHAPTERS, ListSortOrder.RATING -> null } - - private fun timeAgo(date: Date): DateTimeAgo { - val diff = (System.currentTimeMillis() - date.time).coerceAtLeast(0L) - val diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diff).toInt() - val diffDays = -date.daysDiff(System.currentTimeMillis()) - return when { - diffMinutes < 3 -> DateTimeAgo.JustNow - diffDays < 1 -> DateTimeAgo.Today - diffDays == 1 -> DateTimeAgo.Yesterday - diffDays < 6 -> DateTimeAgo.DaysAgo(diffDays) - diffDays < 200 -> DateTimeAgo.MonthsAgo(diffDays / 30) - else -> DateTimeAgo.LongAgo - } - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt index 2f4e20047..b45834d2e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt @@ -24,8 +24,9 @@ import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.resolveDp import org.koitharu.kotatsu.parsers.util.format import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState -import java.text.SimpleDateFormat -import java.util.Date +import java.time.LocalTime +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle import com.google.android.material.R as materialR class ReaderInfoBarView @JvmOverloads constructor( @@ -36,7 +37,7 @@ class ReaderInfoBarView @JvmOverloads constructor( private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private val textBounds = Rect() - private val timeFormat = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT) + private val timeFormat = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) private val timeReceiver = TimeReceiver() private var insetLeft: Int = 0 private var insetRight: Int = 0 @@ -52,7 +53,7 @@ class ReaderInfoBarView @JvmOverloads constructor( 200, ) - private var timeText = timeFormat.format(Date()) + private var timeText = timeFormat.format(LocalTime.now()) private var text: String = "" private val innerHeight @@ -181,7 +182,7 @@ class ReaderInfoBarView @JvmOverloads constructor( private inner class TimeReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - timeText = timeFormat.format(Date()) + timeText = timeFormat.format(LocalTime.now()) invalidate() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index 6b8af28b1..5ce6a348d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -56,7 +56,7 @@ import org.koitharu.kotatsu.reader.domain.DetectReaderModeUseCase import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.config.ReaderSettings import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState -import java.util.Date +import java.time.Instant import javax.inject.Inject private const val BOUNDS_PAGE_OFFSET = 2 @@ -302,7 +302,7 @@ class ReaderViewModel @Inject constructor( page = state.page, scroll = state.scroll, imageUrl = page.preview.ifNullOrEmpty { page.url }, - createdAt = Date(), + createdAt = Instant.now(), percent = computePercent(state.chapterId, state.page), ) bookmarksRepository.addBookmark(bookmark) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/EntityMapping.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/EntityMapping.kt index 3db173650..2f84a7b61 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/EntityMapping.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/data/EntityMapping.kt @@ -3,7 +3,7 @@ package org.koitharu.kotatsu.tracker.data import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem -import java.util.Date +import java.time.Instant fun TrackLogWithManga.toTrackingLogItem(counters: MutableMap): TrackingLogItem { val chaptersList = trackLog.chapters.split('\n').filterNot { x -> x.isEmpty() } @@ -11,7 +11,7 @@ fun TrackLogWithManga.toTrackingLogItem(counters: MutableMap): Tracki id = trackLog.id, chapters = chaptersList, manga = manga.toManga(tags.toMangaTags()), - createdAt = Date(trackLog.createdAt), + createdAt = Instant.ofEpochMilli(trackLog.createdAt), isNew = counters.decrement(trackLog.mangaId, chaptersList.size), ) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt index 663fd9e19..dc0876396 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt @@ -25,7 +25,7 @@ import org.koitharu.kotatsu.tracker.data.toTrackingLogItem import org.koitharu.kotatsu.tracker.domain.model.MangaTracking import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem -import java.util.Date +import java.time.Instant import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import javax.inject.Provider @@ -81,7 +81,7 @@ class TrackingRepository @Inject constructor( result += MangaTracking( manga = manga, lastChapterId = track?.lastChapterId ?: NO_ID, - lastCheck = track?.lastCheck?.takeUnless { it == 0L }?.let(::Date), + lastCheck = track?.lastCheck?.takeUnless { it == 0L }?.let(Instant::ofEpochMilli), ) } return result @@ -93,7 +93,7 @@ class TrackingRepository @Inject constructor( return MangaTracking( manga = manga, lastChapterId = track?.lastChapterId ?: NO_ID, - lastCheck = track?.lastCheck?.takeUnless { it == 0L }?.let(::Date), + lastCheck = track?.lastCheck?.takeUnless { it == 0L }?.let(Instant::ofEpochMilli), ) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaTracking.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaTracking.kt index 67f0eb02c..9f11991b8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaTracking.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaTracking.kt @@ -1,12 +1,12 @@ package org.koitharu.kotatsu.tracker.domain.model -import java.util.* import org.koitharu.kotatsu.parsers.model.Manga +import java.time.Instant data class MangaTracking( val manga: Manga, val lastChapterId: Long, - val lastCheck: Date?, + val lastCheck: Instant?, ) { fun isEmpty(): Boolean { return lastChapterId == 0L diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/TrackingLogItem.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/TrackingLogItem.kt index 286a3a5a4..c6d36b70c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/TrackingLogItem.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/TrackingLogItem.kt @@ -1,12 +1,12 @@ package org.koitharu.kotatsu.tracker.domain.model -import java.util.* import org.koitharu.kotatsu.parsers.model.Manga +import java.time.Instant data class TrackingLogItem( val id: Long, val manga: Manga, val chapters: List, - val createdAt: Date, + val createdAt: Instant, val isNew: Boolean, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt index 7550fad36..48ac6dd48 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/ui/feed/FeedViewModel.kt @@ -15,7 +15,7 @@ import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call -import org.koitharu.kotatsu.core.util.ext.daysDiff +import org.koitharu.kotatsu.core.util.ext.calculateTimeAgo import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.ListHeader @@ -27,8 +27,6 @@ import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem import org.koitharu.kotatsu.tracker.ui.feed.model.UpdatedMangaHeader import org.koitharu.kotatsu.tracker.ui.feed.model.toFeedItem import org.koitharu.kotatsu.tracker.work.TrackWorker -import java.util.Date -import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @@ -99,7 +97,7 @@ class FeedViewModel @Inject constructor( private fun List.mapListTo(destination: MutableList) { var prevDate: DateTimeAgo? = null for (item in this) { - val date = timeAgo(item.createdAt) + val date = calculateTimeAgo(item.createdAt) if (prevDate != date) { destination += ListHeader(date) } @@ -115,17 +113,4 @@ class FeedViewModel @Inject constructor( UpdatedMangaHeader(mangaList.toUi(ListMode.GRID, listExtraProvider)) } } - - private fun timeAgo(date: Date): DateTimeAgo { - val diff = (System.currentTimeMillis() - date.time).coerceAtLeast(0L) - val diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diff).toInt() - val diffDays = -date.daysDiff(System.currentTimeMillis()) - return when { - diffMinutes < 3 -> DateTimeAgo.JustNow - diffDays < 1 -> DateTimeAgo.Today - diffDays == 1 -> DateTimeAgo.Yesterday - diffDays < 6 -> DateTimeAgo.DaysAgo(diffDays) - else -> DateTimeAgo.Absolute(date) - } - } } -- 2.40.1 From 3ae67e1d6cfbbc56b709bbeb7876bbf74f9f8c3d Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Fri, 29 Dec 2023 05:06:35 +0530 Subject: [PATCH 2/2] Revert to Java 8 --- app/build.gradle | 6 +++--- .../org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt | 4 +++- .../main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e1650e5f4..ce29a3572 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,11 +48,11 @@ android { } compileOptions { coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_17 + jvmTarget = JavaVersion.VERSION_1_8.toString() freeCompilerArgs += [ '-opt-in=kotlin.ExperimentalStdlibApi', '-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi', diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt index cbee580f3..ea731925c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/model/DateTimeAgo.kt @@ -75,7 +75,7 @@ sealed class DateTimeAgo { data class Absolute(private val date: LocalDate) : DateTimeAgo() { override fun format(resources: Resources): String { - return if (date == LocalDate.EPOCH) { + return if (date == EPOCH_DATE) { resources.getString(R.string.unknown) } else { date.format(formatter) @@ -85,6 +85,8 @@ sealed class DateTimeAgo { override fun toString() = "abs_${date.toEpochDay()}" companion object { + // TODO: Use Java 9's LocalDate.EPOCH. + private val EPOCH_DATE = LocalDate.of(1970, 1, 1) private val formatter = DateTimeFormatter.ofPattern("d MMMM") } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt index b738cbac0..be2f2e04d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Date.kt @@ -3,11 +3,13 @@ package org.koitharu.kotatsu.core.util.ext import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import java.time.Instant import java.time.LocalDate +import java.time.LocalDateTime import java.time.ZoneId import java.time.temporal.ChronoUnit fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo { - val localDate = LocalDate.ofInstant(instant, ZoneId.systemDefault()) + // TODO: Use Java 9's LocalDate.ofInstant(). + val localDate = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate() val now = LocalDate.now() val diffDays = localDate.until(now, ChronoUnit.DAYS) -- 2.40.1