From 7abec11b558960086cd4110924890338e904521f Mon Sep 17 00:00:00 2001 From: Shinokuni Date: Mon, 5 Aug 2024 17:29:12 +0200 Subject: [PATCH] Replace joda.time by java.time --- api/build.gradle.kts | 1 - .../api/localfeed/atom/ATOMItemAdapter.kt | 4 +- .../api/localfeed/json/JSONItemsAdapter.kt | 4 +- .../api/localfeed/rss1/RSS1ItemAdapter.kt | 4 +- .../api/localfeed/rss2/RSS2ItemAdapter.kt | 4 +- .../freshrss/adapters/FreshRSSItemsAdapter.kt | 6 +- .../adapters/NextcloudNewsItemsAdapter.kt | 5 +- .../java/com/readrops/api/utils/DateUtils.kt | 79 -------------- .../api/localfeed/atom/ATOMAdapterTest.kt | 2 +- .../api/localfeed/json/JSONFeedAdapterTest.kt | 2 +- .../api/localfeed/rss1/RSS1AdapterTest.kt | 2 +- .../api/localfeed/rss2/RSS2AdapterTest.kt | 2 +- .../adapters/FreshRSSItemsAdapterTest.kt | 4 +- .../adapters/NextcloudNewsItemsAdapterTest.kt | 4 +- .../com/readrops/api/utils/DateUtilsTest.java | 58 ---------- app/build.gradle.kts | 1 - .../readrops/app/GetFoldersWithFeedsTest.kt | 2 +- .../readrops/app/SyncResultAnalyserTest.kt | 2 +- .../java/com/readrops/app/item/ItemScreen.kt | 2 +- .../app/repositories/FreshRSSRepository.kt | 3 +- .../repositories/NextcloudNewsRepository.kt | 4 +- .../com/readrops/app/timelime/TimelineItem.kt | 2 +- .../app/timelime/TimelineItemParts.kt | 4 +- .../java/com/readrops/app/DateUtilsTest.kt | 51 +++++++++ db/build.gradle.kts | 2 - db/src/main/java/com/readrops/db/Database.kt | 1 + .../java/com/readrops/db/entities/Item.kt | 2 +- .../com/readrops/db/{ => util}/Converters.kt | 10 +- .../java/com/readrops/db/util/DateUtils.kt | 102 ++++++++++++++++++ gradle/libs.versions.toml | 3 +- 30 files changed, 189 insertions(+), 183 deletions(-) delete mode 100644 api/src/main/java/com/readrops/api/utils/DateUtils.kt delete mode 100644 api/src/test/java/com/readrops/api/utils/DateUtilsTest.java create mode 100644 app/src/test/java/com/readrops/app/DateUtilsTest.kt rename db/src/main/java/com/readrops/db/{ => util}/Converters.kt (66%) create mode 100644 db/src/main/java/com/readrops/db/util/DateUtils.kt diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 93d754fc..692f730e 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -47,5 +47,4 @@ dependencies { implementation(libs.moshi) implementation(libs.jsoup) - implementation(libs.jodatime) } diff --git a/api/src/main/java/com/readrops/api/localfeed/atom/ATOMItemAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/atom/ATOMItemAdapter.kt index aeccdf69..de0cc8df 100644 --- a/api/src/main/java/com/readrops/api/localfeed/atom/ATOMItemAdapter.kt +++ b/api/src/main/java/com/readrops/api/localfeed/atom/ATOMItemAdapter.kt @@ -4,13 +4,13 @@ import com.gitlab.mvysny.konsumexml.Konsumer import com.gitlab.mvysny.konsumexml.Names import com.gitlab.mvysny.konsumexml.allChildrenAutoIgnore import com.readrops.api.localfeed.XmlAdapter -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nonNullText import com.readrops.api.utils.extensions.nullableText import com.readrops.api.utils.extensions.nullableTextRecursively import com.readrops.db.entities.Item -import org.joda.time.LocalDateTime +import com.readrops.db.util.DateUtils +import java.time.LocalDateTime class ATOMItemAdapter : XmlAdapter { diff --git a/api/src/main/java/com/readrops/api/localfeed/json/JSONItemsAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/json/JSONItemsAdapter.kt index f0b67055..1106193a 100644 --- a/api/src/main/java/com/readrops/api/localfeed/json/JSONItemsAdapter.kt +++ b/api/src/main/java/com/readrops/api/localfeed/json/JSONItemsAdapter.kt @@ -1,15 +1,15 @@ package com.readrops.api.localfeed.json import com.readrops.api.localfeed.XmlAdapter.Companion.AUTHORS_MAX -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nextNonEmptyString import com.readrops.api.utils.extensions.nextNullableString import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonReader import com.squareup.moshi.JsonWriter -import org.joda.time.LocalDateTime +import java.time.LocalDateTime class JSONItemsAdapter : JsonAdapter>() { diff --git a/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemAdapter.kt index 4eeaa3b1..ce207bd5 100644 --- a/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemAdapter.kt +++ b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemAdapter.kt @@ -5,13 +5,13 @@ import com.gitlab.mvysny.konsumexml.Names import com.gitlab.mvysny.konsumexml.allChildrenAutoIgnore import com.readrops.api.localfeed.XmlAdapter import com.readrops.api.localfeed.XmlAdapter.Companion.AUTHORS_MAX -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nonNullText import com.readrops.api.utils.extensions.nullableText import com.readrops.api.utils.extensions.nullableTextRecursively import com.readrops.db.entities.Item -import org.joda.time.LocalDateTime +import com.readrops.db.util.DateUtils +import java.time.LocalDateTime class RSS1ItemAdapter : XmlAdapter { diff --git a/api/src/main/java/com/readrops/api/localfeed/rss2/RSS2ItemAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/rss2/RSS2ItemAdapter.kt index 05a59b0b..7adce905 100644 --- a/api/src/main/java/com/readrops/api/localfeed/rss2/RSS2ItemAdapter.kt +++ b/api/src/main/java/com/readrops/api/localfeed/rss2/RSS2ItemAdapter.kt @@ -7,13 +7,13 @@ import com.gitlab.mvysny.konsumexml.allChildrenAutoIgnore import com.readrops.api.localfeed.XmlAdapter import com.readrops.api.localfeed.XmlAdapter.Companion.AUTHORS_MAX import com.readrops.api.utils.ApiUtils -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nonNullText import com.readrops.api.utils.extensions.nullableText import com.readrops.api.utils.extensions.nullableTextRecursively import com.readrops.db.entities.Item -import org.joda.time.LocalDateTime +import com.readrops.db.util.DateUtils +import java.time.LocalDateTime class RSS2ItemAdapter : XmlAdapter { diff --git a/api/src/main/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapter.kt b/api/src/main/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapter.kt index fcc1f51b..e3318b56 100644 --- a/api/src/main/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapter.kt +++ b/api/src/main/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapter.kt @@ -6,11 +6,10 @@ import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nextNonEmptyString import com.readrops.api.utils.extensions.nextNullableString import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonReader import com.squareup.moshi.JsonWriter -import org.joda.time.DateTimeZone -import org.joda.time.LocalDateTime class FreshRSSItemsAdapter : JsonAdapter>() { @@ -46,8 +45,7 @@ class FreshRSSItemsAdapter : JsonAdapter>() { with(item) { when (reader.selectName(NAMES)) { 0 -> remoteId = reader.nextNonEmptyString() - 1 -> pubDate = LocalDateTime(reader.nextLong() * 1000L, - DateTimeZone.getDefault()) + 1 -> pubDate = DateUtils.fromEpochSeconds(reader.nextLong()) 2 -> title = reader.nextNonEmptyString() 3 -> content = getContent(reader) 4 -> link = getLink(reader) diff --git a/api/src/main/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapter.kt b/api/src/main/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapter.kt index d49dcd8a..48046cad 100644 --- a/api/src/main/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapter.kt +++ b/api/src/main/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapter.kt @@ -6,11 +6,10 @@ import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.nextNonEmptyString import com.readrops.api.utils.extensions.nextNullableString import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonReader import com.squareup.moshi.JsonWriter -import org.joda.time.DateTimeZone -import org.joda.time.LocalDateTime class NextcloudNewsItemsAdapter : JsonAdapter>() { @@ -42,7 +41,7 @@ class NextcloudNewsItemsAdapter : JsonAdapter>() { 1 -> link = reader.nextNullableString() 2 -> title = reader.nextNonEmptyString() 3 -> author = reader.nextNullableString() - 4 -> pubDate = LocalDateTime(reader.nextLong() * 1000L, DateTimeZone.getDefault()) + 4 -> pubDate = DateUtils.fromEpochSeconds(reader.nextLong()) 5 -> content = reader.nextNullableString() 6 -> enclosureMime = reader.nextNullableString() 7 -> enclosureLink = reader.nextNullableString() diff --git a/api/src/main/java/com/readrops/api/utils/DateUtils.kt b/api/src/main/java/com/readrops/api/utils/DateUtils.kt deleted file mode 100644 index a765ebee..00000000 --- a/api/src/main/java/com/readrops/api/utils/DateUtils.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.readrops.api.utils - -import org.joda.time.LocalDateTime -import org.joda.time.format.DateTimeFormat -import org.joda.time.format.DateTimeFormatterBuilder -import java.util.Locale - -object DateUtils { - - private val TAG = DateUtils::class.java.simpleName - - /** - * Base of common RSS 2 date formats. - * Examples : - * Fri, 04 Jan 2019 22:21:46 GMT - * Fri, 04 Jan 2019 22:21:46 +0000 - */ - private const val RSS_2_BASE_PATTERN = "EEE, dd MMM yyyy HH:mm:ss" - - private const val GMT_PATTERN = "ZZZ" - - private const val OFFSET_PATTERN = "Z" - - private const val ISO_PATTERN = ".SSSZZ" - - private const val EDT_PATTERN = "zzz" - - /** - * Date pattern for format : 2019-01-04T22:21:46+00:00 - */ - private const val ATOM_JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss" - - @JvmStatic - fun parse(value: String?): LocalDateTime? = if (value == null) { - null - } else try { - val formatter = DateTimeFormatterBuilder() - .appendOptional(DateTimeFormat.forPattern("$RSS_2_BASE_PATTERN ").parser) // with timezone - .appendOptional(DateTimeFormat.forPattern(RSS_2_BASE_PATTERN).parser) // no timezone, important order here - .appendOptional(DateTimeFormat.forPattern(ATOM_JSON_DATE_FORMAT).parser) - .appendOptional(DateTimeFormat.forPattern(GMT_PATTERN).parser) - .appendOptional(DateTimeFormat.forPattern(OFFSET_PATTERN).parser) - .appendOptional(DateTimeFormat.forPattern(ISO_PATTERN).parser) - .appendOptional(DateTimeFormat.forPattern(EDT_PATTERN).parser) - .toFormatter() - .withLocale(Locale.ENGLISH) - .withOffsetParsed() - - formatter.parseLocalDateTime(value) - } catch (e: Exception) { - null - } - - @JvmStatic - fun formattedDateByLocal(dateTime: LocalDateTime): String { - return DateTimeFormat.mediumDate() - .withLocale(Locale.getDefault()) - .print(dateTime) - } - - @JvmStatic - fun formattedDateTimeByLocal(dateTime: LocalDateTime): String { - return DateTimeFormat.forPattern("dd MMM yyyy ยท HH:mm") - .withLocale(Locale.getDefault()) - .print(dateTime) - } - - fun formattedDate(dateTime: LocalDateTime): String { - val pattern = if (dateTime.year != LocalDateTime.now().year) { - "dd MMMM yyyy" - } else { - "dd MMMM" - } - - return DateTimeFormat.forPattern(pattern) - .withLocale(Locale.getDefault()) - .print(dateTime) - } -} \ No newline at end of file diff --git a/api/src/test/java/com/readrops/api/localfeed/atom/ATOMAdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/atom/ATOMAdapterTest.kt index 5a4556e3..18ee69c9 100644 --- a/api/src/test/java/com/readrops/api/localfeed/atom/ATOMAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/localfeed/atom/ATOMAdapterTest.kt @@ -2,8 +2,8 @@ package com.readrops.api.localfeed.atom import com.gitlab.mvysny.konsumexml.konsumeXml import com.readrops.api.TestUtils -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException +import com.readrops.db.util.DateUtils import junit.framework.TestCase import junit.framework.TestCase.assertEquals import org.junit.Assert.assertThrows diff --git a/api/src/test/java/com/readrops/api/localfeed/json/JSONFeedAdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/json/JSONFeedAdapterTest.kt index c5cf8f09..9280fa83 100644 --- a/api/src/test/java/com/readrops/api/localfeed/json/JSONFeedAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/localfeed/json/JSONFeedAdapterTest.kt @@ -1,10 +1,10 @@ package com.readrops.api.localfeed.json import com.readrops.api.TestUtils -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException import com.readrops.db.entities.Feed import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.Moshi import com.squareup.moshi.Types import junit.framework.TestCase diff --git a/api/src/test/java/com/readrops/api/localfeed/rss1/RSS1AdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/rss1/RSS1AdapterTest.kt index 312d38a9..cd1d0f72 100644 --- a/api/src/test/java/com/readrops/api/localfeed/rss1/RSS1AdapterTest.kt +++ b/api/src/test/java/com/readrops/api/localfeed/rss1/RSS1AdapterTest.kt @@ -2,8 +2,8 @@ package com.readrops.api.localfeed.rss1 import com.gitlab.mvysny.konsumexml.konsumeXml import com.readrops.api.TestUtils -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException +import com.readrops.db.util.DateUtils import junit.framework.Assert.assertEquals import junit.framework.Assert.assertNotNull import junit.framework.TestCase diff --git a/api/src/test/java/com/readrops/api/localfeed/rss2/RSS2AdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/rss2/RSS2AdapterTest.kt index a1100296..7e71d15e 100644 --- a/api/src/test/java/com/readrops/api/localfeed/rss2/RSS2AdapterTest.kt +++ b/api/src/test/java/com/readrops/api/localfeed/rss2/RSS2AdapterTest.kt @@ -2,8 +2,8 @@ package com.readrops.api.localfeed.rss2 import com.gitlab.mvysny.konsumexml.konsumeXml import com.readrops.api.TestUtils -import com.readrops.api.utils.DateUtils import com.readrops.api.utils.exceptions.ParseException +import com.readrops.db.util.DateUtils import junit.framework.TestCase import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertTrue diff --git a/api/src/test/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapterTest.kt b/api/src/test/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapterTest.kt index de5ee76d..5d914282 100644 --- a/api/src/test/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/services/freshrss/adapters/FreshRSSItemsAdapterTest.kt @@ -2,12 +2,12 @@ package com.readrops.api.services.freshrss.adapters import com.readrops.api.TestUtils import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.Moshi import com.squareup.moshi.Types import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNotNull import okio.Buffer -import org.joda.time.LocalDateTime import org.junit.Test class FreshRSSItemsAdapterTest { @@ -29,7 +29,7 @@ class FreshRSSItemsAdapterTest { assertNotNull(content) assertEquals(link, "http://feedproxy.google.com/~r/d0od/~3/4Zk-fncSuek/adwaita-borderless-theme-in-development-gnome-41") assertEquals(author, "Joey Sneddon") - assertEquals(pubDate, LocalDateTime(1625234040 * 1000L)) + assertEquals(pubDate, DateUtils.fromEpochSeconds(1625234040)) assertEquals(isRead, false) assertEquals(isStarred, false) } diff --git a/api/src/test/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapterTest.kt b/api/src/test/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapterTest.kt index f7bd6ed6..716acae8 100644 --- a/api/src/test/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/services/nextcloudnews/adapters/NextcloudNewsItemsAdapterTest.kt @@ -2,11 +2,11 @@ package com.readrops.api.services.nextcloudnews.adapters import com.readrops.api.TestUtils import com.readrops.db.entities.Item +import com.readrops.db.util.DateUtils import com.squareup.moshi.Moshi import com.squareup.moshi.Types import junit.framework.TestCase.assertEquals import okio.Buffer -import org.joda.time.LocalDateTime import org.junit.Test class NextcloudNewsItemsAdapterTest { @@ -32,7 +32,7 @@ class NextcloudNewsItemsAdapterTest { assertEquals(feedRemoteId, "67") assertEquals(isRead, false) assertEquals(isStarred, false) - assertEquals(pubDate, LocalDateTime(1367270544000)) + assertEquals(pubDate, DateUtils.fromEpochSeconds(1367270544)) assertEquals(imageLink, null) } diff --git a/api/src/test/java/com/readrops/api/utils/DateUtilsTest.java b/api/src/test/java/com/readrops/api/utils/DateUtilsTest.java deleted file mode 100644 index af3d98c7..00000000 --- a/api/src/test/java/com/readrops/api/utils/DateUtilsTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.readrops.api.utils; - -import org.joda.time.LocalDateTime; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class DateUtilsTest { - - @Test - public void rssDateTest() { - LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46 GMT"))); - } - - @Test - public void rssDate2Test() { - LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46 +0000"))); - } - - @Test - public void rssDate3Test() { - LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46"))); - } - - @Test - public void atomJsonDateTest() { - LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("2019-01-04T22:21:46+00:00"))); - } - - @Test - public void atomJsonDate2Test() { - LocalDateTime dateTime = new LocalDateTime(2019, 1, 4, 22, 21, 46); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("2019-01-04T22:21:46-0000"))); - } - - @Test - public void isoPatternTest() { - LocalDateTime dateTime = new LocalDateTime(2020, 6, 30, 11, 39, 37, 206); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("2020-06-30T11:39:37.206-07:00"))); - } - - @Test - public void edtPatternTest() { - LocalDateTime dateTime = new LocalDateTime(2020, 7, 17, 16, 30, 0); - - assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 17 Jul 2020 16:30:00 EDT"))); - } -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 979807ba..97cc361d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -61,7 +61,6 @@ dependencies { implementation(libs.browser) implementation(libs.jsoup) - implementation(libs.jodatime) testImplementation(libs.junit4) androidTestImplementation(libs.bundles.test) diff --git a/app/src/androidTest/java/com/readrops/app/GetFoldersWithFeedsTest.kt b/app/src/androidTest/java/com/readrops/app/GetFoldersWithFeedsTest.kt index 893095ae..40801a10 100644 --- a/app/src/androidTest/java/com/readrops/app/GetFoldersWithFeedsTest.kt +++ b/app/src/androidTest/java/com/readrops/app/GetFoldersWithFeedsTest.kt @@ -13,7 +13,7 @@ import com.readrops.db.entities.account.AccountType import com.readrops.db.filters.MainFilter import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest -import org.joda.time.LocalDateTime +import java.time.LocalDateTime import org.junit.Before import org.junit.Test import kotlin.test.assertTrue diff --git a/app/src/androidTest/java/com/readrops/app/SyncResultAnalyserTest.kt b/app/src/androidTest/java/com/readrops/app/SyncResultAnalyserTest.kt index 4a63531e..983b428a 100644 --- a/app/src/androidTest/java/com/readrops/app/SyncResultAnalyserTest.kt +++ b/app/src/androidTest/java/com/readrops/app/SyncResultAnalyserTest.kt @@ -12,7 +12,7 @@ import com.readrops.db.entities.Item import com.readrops.db.entities.account.Account import com.readrops.db.entities.account.AccountType import kotlinx.coroutines.test.runTest -import org.joda.time.LocalDateTime +import java.time.LocalDateTime import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/app/src/main/java/com/readrops/app/item/ItemScreen.kt b/app/src/main/java/com/readrops/app/item/ItemScreen.kt index d5a33fe8..e96b40f4 100644 --- a/app/src/main/java/com/readrops/app/item/ItemScreen.kt +++ b/app/src/main/java/com/readrops/app/item/ItemScreen.kt @@ -52,7 +52,6 @@ import androidx.core.view.children import androidx.lifecycle.compose.collectAsStateWithLifecycle import cafe.adriel.voyager.koin.getScreenModel import coil.compose.AsyncImage -import com.readrops.api.utils.DateUtils import com.readrops.app.R import com.readrops.app.item.view.ItemNestedScrollView import com.readrops.app.item.view.ItemWebView @@ -63,6 +62,7 @@ import com.readrops.app.util.theme.MediumSpacer import com.readrops.app.util.theme.ShortSpacer import com.readrops.app.util.theme.spacing import com.readrops.db.pojo.ItemWithFeed +import com.readrops.db.util.DateUtils import org.koin.core.parameter.parametersOf import kotlin.math.roundToInt diff --git a/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.kt b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.kt index 5f8880b9..eb269488 100644 --- a/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.kt +++ b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.kt @@ -12,7 +12,6 @@ import com.readrops.db.entities.Folder import com.readrops.db.entities.Item import com.readrops.db.entities.ItemState import com.readrops.db.entities.account.Account -import org.joda.time.DateTime import org.koin.core.component.KoinComponent class FreshRSSRepository( @@ -63,7 +62,7 @@ class FreshRSSRepository( syncType = SyncType.INITIAL_SYNC } - val newLastModified = DateTime.now().millis / 1000L + val newLastModified = System.currentTimeMillis() / 1000L return dataSource.synchronize(syncType, syncData, account.writeToken!!).run { insertFolders(folders) diff --git a/app/src/main/java/com/readrops/app/repositories/NextcloudNewsRepository.kt b/app/src/main/java/com/readrops/app/repositories/NextcloudNewsRepository.kt index 304f44ef..f695a23c 100644 --- a/app/src/main/java/com/readrops/app/repositories/NextcloudNewsRepository.kt +++ b/app/src/main/java/com/readrops/app/repositories/NextcloudNewsRepository.kt @@ -16,7 +16,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.withContext -import org.joda.time.DateTime import org.koin.core.component.KoinComponent import org.koin.core.component.get @@ -63,7 +62,7 @@ class NextcloudNewsRepository( SyncType.INITIAL_SYNC } - val newLastModified = DateTime.now().millis / 1000L + val newLastModified = System.currentTimeMillis() / 1000L return dataSource.synchronize(syncType, syncData).run { insertFolders(folders) @@ -163,7 +162,6 @@ class NextcloudNewsRepository( itemsFeedsIds[item.feedRemoteId] = feedId } - // TODO itemExists request isn't the right one for this case if (!initialSync && feedId > 0 && database.itemDao().itemExists(item.remoteId!!, feedId)) { database.itemDao() .updateReadAndStarState(item.remoteId!!, item.isRead, item.isStarred) diff --git a/app/src/main/java/com/readrops/app/timelime/TimelineItem.kt b/app/src/main/java/com/readrops/app/timelime/TimelineItem.kt index eb8a88e7..e26c9ef4 100644 --- a/app/src/main/java/com/readrops/app/timelime/TimelineItem.kt +++ b/app/src/main/java/com/readrops/app/timelime/TimelineItem.kt @@ -6,7 +6,7 @@ import com.readrops.app.util.DefaultPreview import com.readrops.app.util.theme.ReadropsTheme import com.readrops.db.entities.Folder import com.readrops.db.pojo.ItemWithFeed -import org.joda.time.LocalDateTime +import java.time.LocalDateTime enum class TimelineItemSize { COMPACT, diff --git a/app/src/main/java/com/readrops/app/timelime/TimelineItemParts.kt b/app/src/main/java/com/readrops/app/timelime/TimelineItemParts.kt index 2f47adfe..7bda6964 100644 --- a/app/src/main/java/com/readrops/app/timelime/TimelineItemParts.kt +++ b/app/src/main/java/com/readrops/app/timelime/TimelineItemParts.kt @@ -34,13 +34,13 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest -import com.readrops.api.utils.DateUtils import com.readrops.app.R import com.readrops.app.util.components.FeedIcon import com.readrops.app.util.theme.ShortSpacer import com.readrops.app.util.theme.spacing import com.readrops.db.pojo.ItemWithFeed -import org.joda.time.LocalDateTime +import com.readrops.db.util.DateUtils +import java.time.LocalDateTime import kotlin.math.roundToInt @Composable diff --git a/app/src/test/java/com/readrops/app/DateUtilsTest.kt b/app/src/test/java/com/readrops/app/DateUtilsTest.kt new file mode 100644 index 00000000..9fa7f28d --- /dev/null +++ b/app/src/test/java/com/readrops/app/DateUtilsTest.kt @@ -0,0 +1,51 @@ +package com.readrops.app + +import com.readrops.db.util.DateUtils +import junit.framework.TestCase.assertEquals +import org.junit.Test +import java.time.LocalDateTime + +class DateUtilsTest { + + @Test + fun rssDateTest() { + val dateTime = LocalDateTime.of(2019, 1, 4, 22, 21, 46) + assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46 GMT"))) + } + + @Test + fun rssDate2Test() { + val dateTime = LocalDateTime.of(2019, 1, 4, 22, 21, 46) + assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46 +0000"))) + } + + @Test + fun rssDate3Test() { + val dateTime = LocalDateTime.of(2019, 1, 4, 22, 21, 46) + assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 04 Jan 2019 22:21:46"))) + } + + @Test + fun edtPatternTest() { + val dateTime = LocalDateTime.of(2020, 7, 17, 16, 30, 0) + assertEquals(0, dateTime.compareTo(DateUtils.parse("Fri, 17 Jul 2020 16:30:00 EDT"))) + } + + @Test + fun atomJsonDateTest() { + val dateTime = LocalDateTime.of(2019, 1, 4, 22, 21, 46) + assertEquals(0, dateTime.compareTo(DateUtils.parse("2019-01-04T22:21:46+00:00"))) + } + + @Test + fun atomJsonDate2Test() { + val dateTime = LocalDateTime.of(2019, 1, 4, 22, 21, 46) + assertEquals(0, dateTime.compareTo(DateUtils.parse("2019-01-04T22:21:46-0000"))) + } + + @Test + fun isoPatternTest() { + val dateTime = LocalDateTime.of(2020, 6, 30, 11, 39, 37, 206000000) + assertEquals(0, dateTime.compareTo(DateUtils.parse("2020-06-30T11:39:37.206-07:00"))) + } +} \ No newline at end of file diff --git a/db/build.gradle.kts b/db/build.gradle.kts index cd1c52ac..aedfbca6 100644 --- a/db/build.gradle.kts +++ b/db/build.gradle.kts @@ -42,8 +42,6 @@ dependencies { implementation(libs.bundles.paging) - implementation(libs.jodatime) - implementation(libs.bundles.koin) testImplementation(libs.bundles.kointest) diff --git a/db/src/main/java/com/readrops/db/Database.kt b/db/src/main/java/com/readrops/db/Database.kt index 426a984e..92c14691 100644 --- a/db/src/main/java/com/readrops/db/Database.kt +++ b/db/src/main/java/com/readrops/db/Database.kt @@ -17,6 +17,7 @@ import com.readrops.db.entities.Item import com.readrops.db.entities.ItemState import com.readrops.db.entities.ItemStateChange import com.readrops.db.entities.account.Account +import com.readrops.db.util.Converters @Database( entities = [Feed::class, Item::class, Folder::class, Account::class, diff --git a/db/src/main/java/com/readrops/db/entities/Item.kt b/db/src/main/java/com/readrops/db/entities/Item.kt index 03b37c30..5c5a2f03 100644 --- a/db/src/main/java/com/readrops/db/entities/Item.kt +++ b/db/src/main/java/com/readrops/db/entities/Item.kt @@ -5,7 +5,7 @@ import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Ignore import androidx.room.PrimaryKey -import org.joda.time.LocalDateTime +import java.time.LocalDateTime @Entity( foreignKeys = [ diff --git a/db/src/main/java/com/readrops/db/Converters.kt b/db/src/main/java/com/readrops/db/util/Converters.kt similarity index 66% rename from db/src/main/java/com/readrops/db/Converters.kt rename to db/src/main/java/com/readrops/db/util/Converters.kt index 91b64589..e0eeb3a5 100644 --- a/db/src/main/java/com/readrops/db/Converters.kt +++ b/db/src/main/java/com/readrops/db/util/Converters.kt @@ -1,24 +1,24 @@ -package com.readrops.db +package com.readrops.db.util import androidx.room.TypeConverter import com.readrops.db.entities.account.AccountType -import org.joda.time.LocalDateTime +import java.time.LocalDateTime class Converters { @TypeConverter fun fromTimeStamp(value: Long): LocalDateTime { - return LocalDateTime(value) + return DateUtils.fromEpochSeconds(value / 1000L) } @TypeConverter fun fromLocalDateTime(localDateTime: LocalDateTime): Long { - return localDateTime.toDateTime().millis + return localDateTime.toInstant(DateUtils.defaultOffset).toEpochMilli() } @TypeConverter fun fromAccountTypeCode(ordinal: Int): AccountType { - return AccountType.values()[ordinal] + return AccountType.entries[ordinal] } @TypeConverter diff --git a/db/src/main/java/com/readrops/db/util/DateUtils.kt b/db/src/main/java/com/readrops/db/util/DateUtils.kt new file mode 100644 index 00000000..feb5843f --- /dev/null +++ b/db/src/main/java/com/readrops/db/util/DateUtils.kt @@ -0,0 +1,102 @@ +package com.readrops.db.util + +import android.annotation.SuppressLint +import android.util.Log +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.format.FormatStyle +import java.util.Locale +import java.util.TimeZone + +object DateUtils { + + private val TAG = DateUtils::class.java.simpleName + + /** + * Base of common RSS 2 date formats. + * Examples : + * Fri, 04 Jan 2019 22:21:46 GMT + * Fri, 04 Jan 2019 22:21:46 +0000 + */ + private const val RSS_2_BASE_PATTERN = "EEE, dd MMM yyyy HH:mm:ss" + + private const val GMT_PATTERN = "ZZZ" + + private const val OFFSET_PATTERN = "Z" + + private const val ISO_PATTERN = ".SSSZZ" + + private const val EDT_PATTERN = "zzz" + + private const val ZONE_OFFSET_PATTERN = ".SSSxxx" + + /** + * Date pattern for format : 2019-01-04T22:21:46+00:00 + */ + private const val ATOM_JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss" + + val defaultOffset: ZoneOffset + get() = OffsetDateTime.now(TimeZone.getDefault().toZoneId()) + .offset + + /** + * Attempts to parse a date string representation. + * If the provided value is null or the parsing fails, [LocalDateTime.now] is returned. + * @return parsed date or [LocalDateTime.now] + */ + @SuppressLint("NewApi") // works with API 21+ so the lint might be buggy + @JvmStatic + fun parse(value: String?): LocalDateTime { + return if (value == null) { + LocalDateTime.now() + } else try { + val formatter = DateTimeFormatterBuilder() + .appendOptional(DateTimeFormatter.ofPattern("$RSS_2_BASE_PATTERN ")) // with timezone + .appendOptional(DateTimeFormatter.ofPattern(RSS_2_BASE_PATTERN)) // no timezone, important order here + .appendOptional(DateTimeFormatter.ofPattern(ATOM_JSON_DATE_FORMAT)) + .appendOptional(DateTimeFormatter.ofPattern(EDT_PATTERN)) + .appendOptional(DateTimeFormatter.ofPattern(ZONE_OFFSET_PATTERN)) + .appendOptional(DateTimeFormatter.ofPattern(GMT_PATTERN)) + .appendOptional(DateTimeFormatter.ofPattern(OFFSET_PATTERN)) + .appendOptional(DateTimeFormatter.ofPattern(ISO_PATTERN)) + .toFormatter() + .withLocale(Locale.ENGLISH) + + LocalDateTime.from(formatter.parse(value)) + } catch (e: Exception) { + Log.d(TAG, "Unable to parse $value: ${e.message}") + LocalDateTime.now() + } + } + + /** + * Be aware of giving a second epoch value and not a millisecond one! + */ + fun fromEpochSeconds(epoch: Long): LocalDateTime { + return LocalDateTime.ofEpochSecond( + epoch, + 0, + defaultOffset + ) + } + + fun formattedDateByLocal(dateTime: LocalDateTime): String { + return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) + .withLocale(Locale.getDefault()) + .format(dateTime) + } + + fun formattedDate(dateTime: LocalDateTime): String { + val pattern = if (dateTime.year != LocalDateTime.now().year) { + "dd MMMM yyyy" + } else { + "dd MMMM" + } + + return DateTimeFormatter.ofPattern(pattern) + .format(dateTime) + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1b36b3a1..25942bd9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,11 +82,10 @@ aboutlibraries-composem3 = { module = "com.mikepenz:aboutlibraries-compose-m3", konsumexml = "com.gitlab.mvysny.konsume-xml:konsume-xml:1.1" kotlinxmlbuilder = "org.redundent:kotlin-xml-builder:1.7.3" #TODO update this -jdk-desugar = "com.android.tools:desugar_jdk_libs:2.0.4" +jdk-desugar = "com.android.tools:desugar_jdk_libs_nio:2.0.4" jsoup = "org.jsoup:jsoup:1.16.1" moshi = "com.squareup.moshi:moshi:1.15.1" -jodatime = "joda-time:joda-time:2.10.10" #TODO replace by java.time # androidx corektx = "androidx.core:core-ktx:1.13.1"