diff --git a/core/network/src/androidMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/DateTimeFormatters.android.kt b/core/network/src/androidMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/DateTimeFormatters.android.kt index 8c5f374df..541fc5005 100644 --- a/core/network/src/androidMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/DateTimeFormatters.android.kt +++ b/core/network/src/androidMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/DateTimeFormatters.android.kt @@ -16,6 +16,8 @@ package dev.sasikanth.rss.reader.core.network.parser +import java.time.Instant +import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -55,61 +57,83 @@ internal actual fun String?.dateStringToEpochMillis(clock: Clock): Long? { for (dateFormatter in dateFormatters) { try { - val parsedValue = dateFormatter.parse(this) + val parsedValue = parseToInstant(dateFormatter, this) + return parsedValue.toEpochMilli() + } catch (e: Exception) { + try { + val parsedValue = fallbackParseToInstant(currentDate, dateFormatter, this) + return parsedValue.toEpochMilli() + } catch (e: Exception) { + // no-op + } + } + } - val year = - try { - parsedValue.get(ChronoField.YEAR) - } catch (e: UnsupportedTemporalTypeException) { - currentDate.get(ChronoField.YEAR) - } - val hourOfDay = - try { - parsedValue.get(ChronoField.HOUR_OF_DAY) - } catch (e: UnsupportedTemporalTypeException) { - 0 - } - val minuteOfHour = - try { - parsedValue.get(ChronoField.MINUTE_OF_HOUR) - } catch (e: UnsupportedTemporalTypeException) { - 0 - } - val secondOfMinute = - try { - parsedValue.get(ChronoField.SECOND_OF_MINUTE) - } catch (e: UnsupportedTemporalTypeException) { - 0 - } - val nanoOfSecond = - try { - parsedValue.get(ChronoField.NANO_OF_SECOND) - } catch (e: UnsupportedTemporalTypeException) { - 0 - } + return null +} - val updatedDate = - currentDate - .withDayOfMonth(parsedValue.get(ChronoField.DAY_OF_MONTH)) - .withMonth(parsedValue.get(ChronoField.MONTH_OF_YEAR)) - .withYear(year) - .withHour(hourOfDay) - .withMinute(minuteOfHour) - .withSecond(secondOfMinute) - .withNano(nanoOfSecond) +private fun parseToInstant(dateTimeFormatter: DateTimeFormatter, text: String): Instant { + return dateTimeFormatter.parse(text, Instant::from) +} + +/** + * In case the date string has values missing from it like year, day, hour, etc., we fill those + * using [currentDate] and then try to convert it to instant. + */ +private fun fallbackParseToInstant( + currentDate: LocalDateTime, + dateTimeFormatter: DateTimeFormatter, + text: String +): Instant { + val parsedValue = dateTimeFormatter.parse(text) + + val year = + try { + parsedValue.get(ChronoField.YEAR) + } catch (e: UnsupportedTemporalTypeException) { + currentDate.get(ChronoField.YEAR) + } + val hourOfDay = + try { + parsedValue.get(ChronoField.HOUR_OF_DAY) + } catch (e: UnsupportedTemporalTypeException) { + 0 + } + val minuteOfHour = + try { + parsedValue.get(ChronoField.MINUTE_OF_HOUR) + } catch (e: UnsupportedTemporalTypeException) { + 0 + } + val secondOfMinute = + try { + parsedValue.get(ChronoField.SECOND_OF_MINUTE) + } catch (e: UnsupportedTemporalTypeException) { + 0 + } + val nanoOfSecond = + try { + parsedValue.get(ChronoField.NANO_OF_SECOND) + } catch (e: UnsupportedTemporalTypeException) { + 0 + } - val zoneId = - try { - ZoneId.from(parsedValue) - } catch (e: Exception) { - TimeZone.UTC.toJavaZoneId() - } + val updatedDate = + currentDate + .withDayOfMonth(parsedValue.get(ChronoField.DAY_OF_MONTH)) + .withMonth(parsedValue.get(ChronoField.MONTH_OF_YEAR)) + .withYear(year) + .withHour(hourOfDay) + .withMinute(minuteOfHour) + .withSecond(secondOfMinute) + .withNano(nanoOfSecond) - return updatedDate.atZone(zoneId).toInstant().toEpochMilli() + val zoneId = + try { + ZoneId.from(parsedValue) } catch (e: Exception) { - // no-op + TimeZone.UTC.toJavaZoneId() } - } - return null + return updatedDate.atZone(zoneId).toInstant() } diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt index b2640a3d6..107dee96a 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/feeds/FeedsPresenter.kt @@ -223,8 +223,9 @@ class FeedsPresenter( } else { feedsPager(postsAfter = postsAfter) } + val feedsWithHeaders = addFeedsHeaders(feeds).cachedIn(coroutineScope) - _state.update { it.copy(feedsInExpandedMode = addFeedsHeaders(feeds)) } + _state.update { it.copy(feedsInExpandedMode = feedsWithHeaders) } } .launchIn(coroutineScope) } @@ -234,7 +235,7 @@ class FeedsPresenter( settingsRepository.postsType.distinctUntilChanged().flatMapLatest { postsType -> val postsAfter = postsAfterInstantFromPostsType(postsType) - feedsPager(postsAfter) + feedsPager(postsAfter).cachedIn(coroutineScope) } observableSelectedFeed.selectedFeed @@ -250,14 +251,12 @@ class FeedsPresenter( rssRepository.searchFeed(searchQuery = transformedSearchQuery, postsAfter = postsAfter) } .flow - .cachedIn(coroutineScope) private fun feedsPager(postsAfter: Instant) = createPager(config = createPagingConfig(pageSize = 20)) { rssRepository.allFeeds(postsAfter = postsAfter) } .flow - .cachedIn(coroutineScope) private fun observeShowUnreadCountPreference() { settingsRepository.showUnreadPostsCount diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/reader/ui/ReaderHTML.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/reader/ui/ReaderHTML.kt index 6edb125be..afd230e7f 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/reader/ui/ReaderHTML.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/reader/ui/ReaderHTML.kt @@ -224,8 +224,6 @@ private object ReaderCSS { iframe { max-width: 100%; max-height: 250px; - border-radius: 28px; - border: 1px solid #fff; } blockquote { margin-left: 8px;