Compare commits

...

3 Commits

Author SHA1 Message Date
Koitharu
8d7f44d2da Fix DateTimeAgo formatting
(cherry picked from commit 5f0514638a)
2025-02-24 18:09:03 +02:00
Koitharu
930d4dfd83 Fix checking for removed manga updates (close #1064)
(cherry picked from commit 1b8d35d424)
2025-02-24 18:07:49 +02:00
Koitharu
290cb652ee Update parsers 2025-02-24 18:05:51 +02:00
7 changed files with 47 additions and 33 deletions

View File

@@ -18,8 +18,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdk = 21 minSdk = 21
targetSdk = 35 targetSdk = 35
versionCode = 702 versionCode = 703
versionName = '7.7.10' versionName = '7.7.11'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp { ksp {

View File

@@ -1,17 +1,18 @@
package org.koitharu.kotatsu.core.ui.model package org.koitharu.kotatsu.core.ui.model
import android.content.res.Resources import android.content.Context
import android.text.format.DateUtils
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.toMillis
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter
sealed class DateTimeAgo { sealed class DateTimeAgo {
abstract fun format(resources: Resources): String abstract fun format(context: Context): String
object JustNow : DateTimeAgo() { object JustNow : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.just_now) return context.getString(R.string.just_now)
} }
override fun toString() = "just_now" override fun toString() = "just_now"
@@ -20,24 +21,32 @@ sealed class DateTimeAgo {
} }
data class MinutesAgo(val minutes: Int) : DateTimeAgo() { data class MinutesAgo(val minutes: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.minutes_ago, minutes, minutes) return context.resources.getQuantityString(
R.plurals.minutes_ago,
minutes,
minutes,
)
} }
override fun toString() = "minutes_ago_$minutes" override fun toString() = "minutes_ago_$minutes"
} }
data class HoursAgo(val hours: Int) : DateTimeAgo() { data class HoursAgo(val hours: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.hours_ago, hours, hours) return context.resources.getQuantityString(
R.plurals.hours_ago,
hours,
hours,
)
} }
override fun toString() = "hours_ago_$hours" override fun toString() = "hours_ago_$hours"
} }
object Today : DateTimeAgo() { object Today : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.today) return context.getString(R.string.today)
} }
override fun toString() = "today" override fun toString() = "today"
@@ -46,8 +55,8 @@ sealed class DateTimeAgo {
} }
object Yesterday : DateTimeAgo() { object Yesterday : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.yesterday) return context.getString(R.string.yesterday)
} }
override fun toString() = "yesterday" override fun toString() = "yesterday"
@@ -56,44 +65,46 @@ sealed class DateTimeAgo {
} }
data class DaysAgo(val days: Int) : DateTimeAgo() { data class DaysAgo(val days: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getQuantityString(R.plurals.days_ago, days, days) return context.resources.getQuantityString(R.plurals.days_ago, days, days)
} }
override fun toString() = "days_ago_$days" override fun toString() = "days_ago_$days"
} }
data class MonthsAgo(val months: Int) : DateTimeAgo() { data class MonthsAgo(val months: Int) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return if (months == 0) { return if (months == 0) {
resources.getString(R.string.this_month) context.getString(R.string.this_month)
} else { } else {
resources.getQuantityString(R.plurals.months_ago, months, months) context.resources.getQuantityString(
R.plurals.months_ago,
months,
months,
)
} }
} }
} }
data class Absolute(private val date: LocalDate) : DateTimeAgo() { data class Absolute(private val date: LocalDate) : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return if (date == EPOCH_DATE) { return if (date == EPOCH_DATE) {
resources.getString(R.string.unknown) context.getString(R.string.unknown)
} else { } else {
date.format(formatter) DateUtils.formatDateTime(context, date.toMillis(), DateUtils.FORMAT_SHOW_DATE)
} }
} }
override fun toString() = "abs_${date.toEpochDay()}" override fun toString() = "abs_${date.toEpochDay()}"
companion object { private companion object {
// TODO: Use Java 9's LocalDate.EPOCH. val EPOCH_DATE: LocalDate = LocalDate.of(1970, 1, 1)
private val EPOCH_DATE = LocalDate.of(1970, 1, 1)
private val formatter = DateTimeFormatter.ofPattern("d MMMM")
} }
} }
object LongAgo : DateTimeAgo() { object LongAgo : DateTimeAgo() {
override fun format(resources: Resources): String { override fun format(context: Context): String {
return resources.getString(R.string.long_ago) return context.getString(R.string.long_ago)
} }
override fun toString() = "long_ago" override fun toString() = "long_ago"

View File

@@ -35,6 +35,7 @@ fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo
} }
} }
@Suppress("KotlinConstantConditions")
fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this) fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this)
fun Resources.formatDurationShort(millis: Long): String? { fun Resources.formatDurationShort(millis: Long): String? {
@@ -50,3 +51,5 @@ fun Resources.formatDurationShort(millis: Long): String? {
else -> getString(R.string.seconds_short, seconds) else -> getString(R.string.seconds_short, seconds)
} }
} }
fun LocalDate.toMillis(): Long = atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()

View File

@@ -36,7 +36,7 @@ data class ListHeader private constructor(
fun getText(context: Context): CharSequence? = when (textRaw) { fun getText(context: Context): CharSequence? = when (textRaw) {
is CharSequence -> textRaw is CharSequence -> textRaw
is Int -> if (textRaw != 0) context.getString(textRaw) else null is Int -> if (textRaw != 0) context.getString(textRaw) else null
is DateTimeAgo -> textRaw.format(context.resources) is DateTimeAgo -> textRaw.format(context)
else -> null else -> null
} }

View File

@@ -37,7 +37,7 @@ class MangaStatsSheet : BaseAdaptiveSheet<SheetStatsMangaBinding>(), View.OnClic
binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga) binding.chartView.barColor = KotatsuColors.ofManga(binding.root.context, viewModel.manga)
viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged) viewModel.stats.observe(viewLifecycleOwner, ::onStatsChanged)
viewModel.startDate.observe(viewLifecycleOwner) { viewModel.startDate.observe(viewLifecycleOwner) {
binding.textViewStart.textAndVisible = it?.format(resources) binding.textViewStart.textAndVisible = it?.format(binding.root.context)
} }
viewModel.totalPagesRead.observe(viewLifecycleOwner) { viewModel.totalPagesRead.observe(viewLifecycleOwner) {
binding.textViewPages.text = getString(R.string.pages_read_s, it.format()) binding.textViewPages.text = getString(R.string.pages_read_s, it.format())

View File

@@ -67,7 +67,7 @@ abstract class TracksDao : MangaQueryBuilder.ConditionCallback {
@Query("DELETE FROM tracks WHERE manga_id = :mangaId") @Query("DELETE FROM tracks WHERE manga_id = :mangaId")
abstract suspend fun delete(mangaId: Long) abstract suspend fun delete(mangaId: Long)
@Query("DELETE FROM tracks WHERE manga_id NOT IN (SELECT manga_id FROM history UNION SELECT manga_id FROM favourites WHERE category_id IN (SELECT category_id FROM favourite_categories WHERE track = 1))") @Query("DELETE FROM tracks WHERE manga_id NOT IN (SELECT manga_id FROM history WHERE history.deleted_at = 0 UNION SELECT manga_id FROM favourites WHERE favourites.deleted_at = 0 AND category_id IN (SELECT category_id FROM favourite_categories WHERE favourite_categories.deleted_at = 0 AND track = 1))")
abstract suspend fun gc() abstract suspend fun gc()
@Upsert @Upsert

View File

@@ -31,7 +31,7 @@ material = "1.12.0"
moshi = "1.15.2" moshi = "1.15.2"
okhttp = "4.12.0" okhttp = "4.12.0"
okio = "3.9.1" okio = "3.9.1"
parsers = "794a737b6d" parsers = "1.6"
preference = "1.2.1" preference = "1.2.1"
recyclerview = "1.3.2" recyclerview = "1.3.2"
room = "2.6.1" room = "2.6.1"