From 88b687f57b6e564dca8364f663653184e516b0ab Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Sat, 13 Sep 2025 05:35:03 +0530 Subject: [PATCH] Refactor codebase to use Instant instead of OffsetDateTime --- .../newpipe/database/DatabaseMigrationTest.kt | 4 +- .../org/schabi/newpipe/database/Converters.kt | 18 +++---- .../newpipe/database/feed/dao/FeedDAO.kt | 24 ++++----- .../feed/model/FeedLastUpdatedEntity.kt | 4 +- .../history/model/SearchHistoryEntry.kt | 15 ++---- .../history/model/StreamHistoryEntity.java | 18 +++---- .../history/model/StreamHistoryEntry.kt | 14 +---- .../database/stream/StreamStatisticsEntry.kt | 4 +- .../newpipe/database/stream/dao/StreamDAO.kt | 10 ++-- .../database/stream/model/StreamEntity.kt | 16 +++--- .../fragments/detail/DescriptionFragment.java | 11 ++-- .../list/comments/CommentRepliesFragment.java | 2 +- .../holder/CommentInfoItemHolder.java | 13 ++--- .../holder/StreamInfoItemHolder.java | 2 +- .../newpipe/local/feed/FeedDatabaseManager.kt | 53 +++++++++---------- .../schabi/newpipe/local/feed/FeedFragment.kt | 15 +++--- .../schabi/newpipe/local/feed/FeedState.kt | 4 +- .../newpipe/local/feed/FeedViewModel.kt | 10 ++-- .../newpipe/local/feed/item/StreamItem.kt | 4 +- .../local/feed/service/FeedLoadManager.kt | 30 +++++------ .../local/history/HistoryRecordManager.java | 13 +++-- .../history/StatisticsPlaylistFragment.java | 2 +- .../LocalStatisticStreamItemHolder.java | 2 +- .../org/schabi/newpipe/util/Localization.java | 35 ++++++------ .../schabi/newpipe/util/LocalizationTest.kt | 20 ++++--- 25 files changed, 159 insertions(+), 184 deletions(-) diff --git a/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt b/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt index a34cfece6..0cf0ce26e 100644 --- a/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt +++ b/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt @@ -144,7 +144,7 @@ class DatabaseMigrationTest { assertEquals(DEFAULT_THUMBNAIL, streamFromMigratedDatabase.thumbnailUrl) assertNull(streamFromMigratedDatabase.viewCount) assertNull(streamFromMigratedDatabase.textualUploadDate) - assertNull(streamFromMigratedDatabase.uploadDate) + assertNull(streamFromMigratedDatabase.uploadInstant) assertNull(streamFromMigratedDatabase.isUploadDateApproximation) val secondStreamFromMigratedDatabase = listFromDB[1] @@ -158,7 +158,7 @@ class DatabaseMigrationTest { assertEquals("", secondStreamFromMigratedDatabase.thumbnailUrl) assertNull(secondStreamFromMigratedDatabase.viewCount) assertNull(secondStreamFromMigratedDatabase.textualUploadDate) - assertNull(secondStreamFromMigratedDatabase.uploadDate) + assertNull(secondStreamFromMigratedDatabase.uploadInstant) assertNull(secondStreamFromMigratedDatabase.isUploadDateApproximation) } diff --git a/app/src/main/java/org/schabi/newpipe/database/Converters.kt b/app/src/main/java/org/schabi/newpipe/database/Converters.kt index ec097cc1b..efd351fb1 100644 --- a/app/src/main/java/org/schabi/newpipe/database/Converters.kt +++ b/app/src/main/java/org/schabi/newpipe/database/Converters.kt @@ -4,31 +4,27 @@ import androidx.room.TypeConverter import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.local.subscription.FeedGroupIcon import java.time.Instant -import java.time.OffsetDateTime -import java.time.ZoneOffset class Converters { /** - * Convert a long value to a [OffsetDateTime]. + * Convert a long value to an [Instant]. * * @param value the long value - * @return the `OffsetDateTime` + * @return the `Instant` */ @TypeConverter - fun offsetDateTimeFromTimestamp(value: Long?): OffsetDateTime? { - return value?.let { OffsetDateTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC) } + fun timestampToInstant(value: Long?): Instant? { + return value?.let { Instant.ofEpochMilli(it) } } /** - * Convert a [OffsetDateTime] to a long value. + * Convert an [Instant] to a long value. * - * @param offsetDateTime the `OffsetDateTime` + * @param instant the `Instant` * @return the long value */ @TypeConverter - fun offsetDateTimeToTimestamp(offsetDateTime: OffsetDateTime?): Long? { - return offsetDateTime?.withOffsetSameInstant(ZoneOffset.UTC)?.toInstant()?.toEpochMilli() - } + fun instantToTimestamp(instant: Instant?) = instant?.toEpochMilli() @TypeConverter fun streamTypeOf(value: String): StreamType { diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt index e7ed93497..06055a764 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt @@ -15,7 +15,7 @@ import org.schabi.newpipe.database.stream.StreamWithState import org.schabi.newpipe.database.stream.model.StreamStateEntity import org.schabi.newpipe.database.subscription.NotificationMode import org.schabi.newpipe.database.subscription.SubscriptionEntity -import java.time.OffsetDateTime +import java.time.Instant @Dao abstract class FeedDAO { @@ -90,7 +90,7 @@ abstract class FeedDAO { groupId: Long, includePlayed: Boolean, includePartiallyPlayed: Boolean, - uploadDateBefore: OffsetDateTime? + uploadDateBefore: Instant? ): Maybe> /** @@ -99,7 +99,7 @@ abstract class FeedDAO { * * One stream per uploader is kept because it is needed as reference * when fetching new streams to check if they are new or not. - * @param offsetDateTime the newest date to keep, older streams are removed + * @param instant the newest date to keep, older streams are removed */ @Query( """ @@ -115,11 +115,11 @@ abstract class FeedDAO { INNER JOIN feed f ON s.uid = f.stream_id - WHERE s.upload_date < :offsetDateTime + WHERE s.upload_date < :instant AND s.upload_date <> max_upload_date)) """ ) - abstract fun unlinkStreamsOlderThan(offsetDateTime: OffsetDateTime) + abstract fun unlinkStreamsOlderThan(instant: Instant) @Query( """ @@ -168,13 +168,13 @@ abstract class FeedDAO { ON fgs.subscription_id = lu.subscription_id AND fgs.group_id = :groupId """ ) - abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable> + abstract fun getOldestSubscriptionUpdate(groupId: Long): Flowable> @Query("SELECT MIN(last_updated) FROM feed_last_updated") - abstract fun oldestSubscriptionUpdateFromAll(): Flowable> + abstract fun getOldestSubscriptionUpdateFromAll(): Flowable> @Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL") - abstract fun notLoadedCount(): Flowable + abstract fun getNotLoadedCount(): Flowable @Query( """ @@ -189,7 +189,7 @@ abstract class FeedDAO { WHERE lu.last_updated IS NULL """ ) - abstract fun notLoadedCountForGroup(groupId: Long): Flowable + abstract fun getNotLoadedCountForGroup(groupId: Long): Flowable @Query( """ @@ -201,7 +201,7 @@ abstract class FeedDAO { WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold """ ) - abstract fun getAllOutdated(outdatedThreshold: OffsetDateTime): Flowable> + abstract fun getAllOutdated(outdatedThreshold: Instant): Flowable> @Query( """ @@ -216,7 +216,7 @@ abstract class FeedDAO { WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold """ ) - abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: OffsetDateTime): Flowable> + abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: Instant): Flowable> @Query( """ @@ -231,7 +231,7 @@ abstract class FeedDAO { """ ) abstract fun getOutdatedWithNotificationMode( - outdatedThreshold: OffsetDateTime, + outdatedThreshold: Instant, @NotificationMode notificationMode: Int ): Flowable> } diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedLastUpdatedEntity.kt b/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedLastUpdatedEntity.kt index a19af9c45..217bfd860 100644 --- a/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedLastUpdatedEntity.kt +++ b/app/src/main/java/org/schabi/newpipe/database/feed/model/FeedLastUpdatedEntity.kt @@ -7,7 +7,7 @@ import androidx.room.PrimaryKey import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID import org.schabi.newpipe.database.subscription.SubscriptionEntity -import java.time.OffsetDateTime +import java.time.Instant @Entity( tableName = FEED_LAST_UPDATED_TABLE, @@ -26,7 +26,7 @@ data class FeedLastUpdatedEntity( var subscriptionId: Long, @ColumnInfo(name = LAST_UPDATED) - var lastUpdated: OffsetDateTime? = null + var lastUpdated: Instant? = null ) { companion object { const val FEED_LAST_UPDATED_TABLE = "feed_last_updated" diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt b/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt index 8cb9a25ca..d8c8e97d4 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt +++ b/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt @@ -5,18 +5,16 @@ import androidx.room.Entity import androidx.room.Ignore import androidx.room.Index import androidx.room.PrimaryKey -import java.time.OffsetDateTime +import java.time.Instant @Entity( tableName = SearchHistoryEntry.TABLE_NAME, indices = [Index(value = [SearchHistoryEntry.SEARCH])] ) data class SearchHistoryEntry( - @field:ColumnInfo(name = CREATION_DATE) var creationDate: OffsetDateTime?, - @field:ColumnInfo( - name = SERVICE_ID - ) var serviceId: Int, - @field:ColumnInfo(name = SEARCH) var search: String? + @ColumnInfo(name = CREATION_DATE) var creationInstant: Instant?, + @ColumnInfo(name = SERVICE_ID) var serviceId: Int, + @ColumnInfo(name = SEARCH) var search: String? ) { @ColumnInfo(name = ID) @PrimaryKey(autoGenerate = true) @@ -24,10 +22,7 @@ data class SearchHistoryEntry( @Ignore fun hasEqualValues(otherEntry: SearchHistoryEntry): Boolean { - return ( - serviceId == otherEntry.serviceId && - search == otherEntry.search - ) + return serviceId == otherEntry.serviceId && search == otherEntry.search } companion object { diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java index a9d69afe8..f22160643 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java @@ -8,7 +8,7 @@ import androidx.room.Index; import org.schabi.newpipe.database.stream.model.StreamEntity; -import java.time.OffsetDateTime; +import java.time.Instant; import static androidx.room.ForeignKey.CASCADE; import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID; @@ -36,21 +36,21 @@ public class StreamHistoryEntity { @NonNull @ColumnInfo(name = STREAM_ACCESS_DATE) - private OffsetDateTime accessDate; + private Instant accessInstant; @ColumnInfo(name = STREAM_REPEAT_COUNT) private long repeatCount; /** * @param streamUid the stream id this history item will refer to - * @param accessDate the last time the stream was accessed + * @param accessInstant the last time the stream was accessed * @param repeatCount the total number of views this stream received */ public StreamHistoryEntity(final long streamUid, - @NonNull final OffsetDateTime accessDate, + @NonNull final Instant accessInstant, final long repeatCount) { this.streamUid = streamUid; - this.accessDate = accessDate; + this.accessInstant = accessInstant; this.repeatCount = repeatCount; } @@ -63,12 +63,12 @@ public class StreamHistoryEntity { } @NonNull - public OffsetDateTime getAccessDate() { - return accessDate; + public Instant getAccessInstant() { + return accessInstant; } - public void setAccessDate(@NonNull final OffsetDateTime accessDate) { - this.accessDate = accessDate; + public void setAccessInstant(@NonNull final Instant accessInstant) { + this.accessInstant = accessInstant; } public long getRepeatCount() { diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntry.kt b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntry.kt index 27fc429f1..41bd5323f 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntry.kt +++ b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntry.kt @@ -5,7 +5,7 @@ import androidx.room.Embedded import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.util.image.ImageStrategy -import java.time.OffsetDateTime +import java.time.Instant data class StreamHistoryEntry( @Embedded @@ -15,21 +15,11 @@ data class StreamHistoryEntry( val streamId: Long, @ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE) - val accessDate: OffsetDateTime, + val accessInstant: Instant, @ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT) val repeatCount: Long ) { - - fun toStreamHistoryEntity(): StreamHistoryEntity { - return StreamHistoryEntity(streamId, accessDate, repeatCount) - } - - fun hasEqualValues(other: StreamHistoryEntry): Boolean { - return this.streamEntity.uid == other.streamEntity.uid && streamId == other.streamId && - accessDate.isEqual(other.accessDate) - } - fun toStreamInfoItem(): StreamInfoItem = StreamInfoItem( streamEntity.serviceId, diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt index 1f3654e7a..87444a535 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt +++ b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt @@ -8,7 +8,7 @@ import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.util.image.ImageStrategy -import java.time.OffsetDateTime +import java.time.Instant class StreamStatisticsEntry( @Embedded @@ -21,7 +21,7 @@ class StreamStatisticsEntry( val streamId: Long, @ColumnInfo(name = STREAM_LATEST_DATE) - val latestAccessDate: OffsetDateTime, + val latestAccessInstant: Instant, @ColumnInfo(name = STREAM_WATCH_COUNT) val watchCount: Long diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamDAO.kt b/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamDAO.kt index d8c19c1e9..50adbfe26 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamDAO.kt +++ b/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamDAO.kt @@ -13,7 +13,7 @@ import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.util.StreamTypeUtil -import java.time.OffsetDateTime +import java.time.Instant @Dao abstract class StreamDAO : BasicDAO { @@ -95,9 +95,9 @@ abstract class StreamDAO : BasicDAO { // Use the existent upload date if the newer stream does not have a better precision // (i.e. is an approximation). This is done to prevent unnecessary changes. val hasBetterPrecision = - newerStream.uploadDate != null && newerStream.isUploadDateApproximation != true - if (existentMinimalStream.uploadDate != null && !hasBetterPrecision) { - newerStream.uploadDate = existentMinimalStream.uploadDate + newerStream.uploadInstant != null && newerStream.isUploadDateApproximation != true + if (existentMinimalStream.uploadInstant != null && !hasBetterPrecision) { + newerStream.uploadInstant = existentMinimalStream.uploadInstant newerStream.textualUploadDate = existentMinimalStream.textualUploadDate newerStream.isUploadDateApproximation = existentMinimalStream.isUploadDateApproximation } @@ -138,7 +138,7 @@ abstract class StreamDAO : BasicDAO { var textualUploadDate: String? = null, @ColumnInfo(name = StreamEntity.STREAM_UPLOAD_DATE) - var uploadDate: OffsetDateTime? = null, + var uploadInstant: Instant? = null, @ColumnInfo(name = StreamEntity.STREAM_IS_UPLOAD_DATE_APPROXIMATION) var isUploadDateApproximation: Boolean? = null, diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt index d9c160b89..eeebc4199 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt +++ b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt @@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.player.playqueue.PlayQueueItem import org.schabi.newpipe.util.image.ImageStrategy import java.io.Serializable -import java.time.OffsetDateTime +import java.time.Instant @Entity( tableName = STREAM_TABLE, @@ -59,7 +59,7 @@ data class StreamEntity( var textualUploadDate: String? = null, @ColumnInfo(name = STREAM_UPLOAD_DATE) - var uploadDate: OffsetDateTime? = null, + var uploadInstant: Instant? = null, @ColumnInfo(name = STREAM_IS_UPLOAD_DATE_APPROXIMATION) var isUploadDateApproximation: Boolean? = null @@ -69,8 +69,9 @@ data class StreamEntity( serviceId = item.serviceId, url = item.url, title = item.name, streamType = item.streamType, duration = item.duration, uploader = item.uploaderName, uploaderUrl = item.uploaderUrl, - thumbnailUrl = ImageStrategy.imageListToDbUrl(item.thumbnails), viewCount = item.viewCount, - textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(), + thumbnailUrl = ImageStrategy.imageListToDbUrl(item.thumbnails), + viewCount = item.viewCount, textualUploadDate = item.textualUploadDate, + uploadInstant = item.uploadDate?.instant, isUploadDateApproximation = item.uploadDate?.isApproximation ) @@ -79,8 +80,9 @@ data class StreamEntity( serviceId = info.serviceId, url = info.url, title = info.name, streamType = info.streamType, duration = info.duration, uploader = info.uploaderName, uploaderUrl = info.uploaderUrl, - thumbnailUrl = ImageStrategy.imageListToDbUrl(info.thumbnails), viewCount = info.viewCount, - textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(), + thumbnailUrl = ImageStrategy.imageListToDbUrl(info.thumbnails), + viewCount = info.viewCount, + textualUploadDate = info.textualUploadDate, uploadInstant = info.uploadDate?.instant, isUploadDateApproximation = info.uploadDate?.isApproximation ) @@ -101,7 +103,7 @@ data class StreamEntity( if (viewCount != null) item.viewCount = viewCount as Long item.textualUploadDate = textualUploadDate - item.uploadDate = uploadDate?.let { + item.uploadDate = uploadInstant?.let { DateWrapper(it, isUploadDateApproximation ?: false) } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java index 2b0d22a32..e5e09ad83 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java @@ -65,11 +65,12 @@ public class DescriptionFragment extends BaseDescriptionFragment { } @Override - protected void setupMetadata(final LayoutInflater inflater, - final LinearLayout layout) { - if (streamInfo != null && streamInfo.getUploadDate() != null) { - binding.detailUploadDateView.setText(Localization - .localizeUploadDate(activity, streamInfo.getUploadDate().offsetDateTime())); + protected void setupMetadata(final LayoutInflater inflater, final LinearLayout layout) { + final var uploadDate = streamInfo != null ? streamInfo.getUploadDate() : null; + if (uploadDate != null) { + final String formattedDate = activity.getString(R.string.upload_date_text, + Localization.formatDate(uploadDate)); + binding.detailUploadDateView.setText(formattedDate); } else { binding.detailUploadDateView.setVisibility(View.GONE); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.java index ce52c029d..816ee9bf4 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.java @@ -90,7 +90,7 @@ public final class CommentRepliesFragment // setup author name and comment date binding.authorName.setText(item.getUploaderName()); - binding.uploadDate.setText(Localization.relativeTimeOrTextual( + binding.uploadDate.setText(Localization.formatRelativeTimeOrTextual( getContext(), item.getUploadDate(), item.getTextualUploadDate())); binding.authorTouchArea.setOnClickListener( v -> NavigationHelper.openCommentAuthorIfPresent(requireActivity(), item)); diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java index a19831cc7..7c9deb4b9 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java @@ -82,11 +82,9 @@ public class CommentInfoItemHolder extends InfoItemHolder { @Override public void updateFromItem(final InfoItem infoItem, final HistoryRecordManager historyRecordManager) { - if (!(infoItem instanceof CommentsInfoItem)) { + if (!(infoItem instanceof CommentsInfoItem item)) { return; } - final CommentsInfoItem item = (CommentsInfoItem) infoItem; - // load the author avatar PicassoHelper.loadAvatar(item.getUploaderAvatars()).into(itemThumbnailView); @@ -104,12 +102,9 @@ public class CommentInfoItemHolder extends InfoItemHolder { // setup the top row, with pinned icon, author name and comment date itemPinnedView.setVisibility(item.isPinned() ? View.VISIBLE : View.GONE); final String uploaderName = Localization.localizeUserName(item.getUploaderName()); - itemTitleView.setText(Localization.concatenateStrings( - uploaderName, - Localization.relativeTimeOrTextual( - itemBuilder.getContext(), - item.getUploadDate(), - item.getTextualUploadDate()))); + final String relativeTime = Localization.formatRelativeTimeOrTextual( + itemBuilder.getContext(), item.getUploadDate(), item.getTextualUploadDate()); + itemTitleView.setText(Localization.concatenateStrings(uploaderName, relativeTime)); // setup bottom row, with likes, heart and replies button itemLikesCountView.setText( diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java index 80f62eed3..dfd10e980 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamInfoItemHolder.java @@ -77,7 +77,7 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder { } } - final String uploadDate = Localization.relativeTimeOrTextual(itemBuilder.getContext(), + final String uploadDate = Localization.formatRelativeTimeOrTextual(itemBuilder.getContext(), infoItem.getUploadDate(), infoItem.getTextualUploadDate()); if (!TextUtils.isEmpty(uploadDate)) { diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt index ed65d4048..60fb5b09c 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt @@ -18,9 +18,9 @@ import org.schabi.newpipe.database.subscription.NotificationMode import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.local.subscription.FeedGroupIcon +import java.time.Instant import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneOffset +import java.time.ZoneId class FeedDatabaseManager(context: Context) { private val database = NewPipeDatabase.getInstance(context) @@ -32,8 +32,7 @@ class FeedDatabaseManager(context: Context) { /** * Only items that are newer than this will be saved. */ - val FEED_OLDEST_ALLOWED_DATE: OffsetDateTime = LocalDate.now().minusWeeks(13) - .atStartOfDay().atOffset(ZoneOffset.UTC) + val FEED_OLDEST_ALLOWED_DATE: LocalDate = LocalDate.now().minusWeeks(13) } fun groups() = feedGroupTable.getAll() @@ -50,27 +49,27 @@ class FeedDatabaseManager(context: Context) { groupId, includePlayedStreams, includePartiallyPlayedStreams, - if (includeFutureStreams) null else OffsetDateTime.now() + if (includeFutureStreams) null else Instant.now() ) } - fun outdatedSubscriptions(outdatedThreshold: OffsetDateTime) = feedTable.getAllOutdated(outdatedThreshold) + fun getOutdatedSubscriptions(outdatedThreshold: Instant) = feedTable.getAllOutdated(outdatedThreshold) - fun outdatedSubscriptionsWithNotificationMode( - outdatedThreshold: OffsetDateTime, + fun getOutdatedSubscriptionsWithNotificationMode( + outdatedThreshold: Instant, @NotificationMode notificationMode: Int ) = feedTable.getOutdatedWithNotificationMode(outdatedThreshold, notificationMode) - fun notLoadedCount(groupId: Long = FeedGroupEntity.GROUP_ALL_ID): Flowable { + fun getNotLoadedCount(groupId: Long = FeedGroupEntity.GROUP_ALL_ID): Flowable { return when (groupId) { - FeedGroupEntity.GROUP_ALL_ID -> feedTable.notLoadedCount() - else -> feedTable.notLoadedCountForGroup(groupId) + FeedGroupEntity.GROUP_ALL_ID -> feedTable.getNotLoadedCount() + else -> feedTable.getNotLoadedCountForGroup(groupId) } } - fun outdatedSubscriptionsForGroup( + fun getOutdatedSubscriptionsForGroup( groupId: Long = FeedGroupEntity.GROUP_ALL_ID, - outdatedThreshold: OffsetDateTime + outdatedThreshold: Instant ) = feedTable.getAllOutdatedForGroup(groupId, outdatedThreshold) fun markAsOutdated(subscriptionId: Long) = feedTable @@ -83,17 +82,14 @@ class FeedDatabaseManager(context: Context) { fun upsertAll( subscriptionId: Long, items: List, - oldestAllowedDate: OffsetDateTime = FEED_OLDEST_ALLOWED_DATE + oldestAllowedDate: LocalDate = FEED_OLDEST_ALLOWED_DATE ) { - val itemsToInsert = ArrayList() - loop@ for (streamItem in items) { - val uploadDate = streamItem.uploadDate + val zoneId = ZoneId.systemDefault() + val itemsToInsert = items.filter { + val uploadDate = it.uploadDate?.let { LocalDate.ofInstant(it.instant, zoneId) } - itemsToInsert += when { - uploadDate == null && streamItem.streamType == StreamType.LIVE_STREAM -> streamItem - uploadDate != null && uploadDate.offsetDateTime() >= oldestAllowedDate -> streamItem - else -> continue@loop - } + (uploadDate == null && it.streamType == StreamType.LIVE_STREAM) || + (uploadDate != null && uploadDate >= oldestAllowedDate) } feedTable.unlinkOldLivestreams(subscriptionId) @@ -107,12 +103,13 @@ class FeedDatabaseManager(context: Context) { } feedTable.setLastUpdatedForSubscription( - FeedLastUpdatedEntity(subscriptionId, OffsetDateTime.now(ZoneOffset.UTC)) + FeedLastUpdatedEntity(subscriptionId, Instant.now()) ) } - fun removeOrphansOrOlderStreams(oldestAllowedDate: OffsetDateTime = FEED_OLDEST_ALLOWED_DATE) { - feedTable.unlinkStreamsOlderThan(oldestAllowedDate) + fun removeOrphansOrOlderStreams(oldestAllowedDate: LocalDate = FEED_OLDEST_ALLOWED_DATE) { + val instant = oldestAllowedDate.atStartOfDay(ZoneId.systemDefault()).toInstant() + feedTable.unlinkStreamsOlderThan(instant) streamTable.deleteOrphans() } @@ -177,10 +174,10 @@ class FeedDatabaseManager(context: Context) { .observeOn(AndroidSchedulers.mainThread()) } - fun oldestSubscriptionUpdate(groupId: Long): Flowable> { + fun oldestSubscriptionUpdate(groupId: Long): Flowable> { return when (groupId) { - FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll() - else -> feedTable.oldestSubscriptionUpdate(groupId) + FeedGroupEntity.GROUP_ALL_ID -> feedTable.getOldestSubscriptionUpdateFromAll() + else -> feedTable.getOldestSubscriptionUpdate(groupId) } } } diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 91f98f5d2..37b845e8d 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -81,7 +81,7 @@ import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountStreams import org.schabi.newpipe.util.ThemeHelper.getItemViewMode import org.schabi.newpipe.util.ThemeHelper.resolveDrawable import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout -import java.time.OffsetDateTime +import java.time.Instant import java.util.function.Consumer class FeedFragment : BaseStateFragment() { @@ -95,7 +95,7 @@ class FeedFragment : BaseStateFragment() { private var groupId = FeedGroupEntity.GROUP_ALL_ID private var groupName = "" - private var oldestSubscriptionUpdate: OffsetDateTime? = null + private var oldestSubscriptionUpdate: Instant? = null private lateinit var groupAdapter: GroupieAdapter @@ -415,8 +415,8 @@ class FeedFragment : BaseStateFragment() { val oldOldestSubscriptionUpdate = oldestSubscriptionUpdate groupAdapter.updateAsync(loadedState.items, false) { - oldOldestSubscriptionUpdate?.run { - highlightNewItemsAfter(oldOldestSubscriptionUpdate) + oldOldestSubscriptionUpdate?.let { + highlightNewItemsAfter(it) } } @@ -543,14 +543,14 @@ class FeedFragment : BaseStateFragment() { private fun updateRefreshViewState() { feedBinding.refreshText.text = getString( R.string.feed_oldest_subscription_update, - oldestSubscriptionUpdate?.let { Localization.relativeTime(it) } ?: "—" + oldestSubscriptionUpdate?.let { Localization.formatRelativeTime(it) } ?: "—" ) } /** * Highlights all items that are after the specified time */ - private fun highlightNewItemsAfter(updateTime: OffsetDateTime) { + private fun highlightNewItemsAfter(updateTime: Instant) { var highlightCount = 0 var doCheck = true @@ -563,8 +563,9 @@ class FeedFragment : BaseStateFragment() { resolveDrawable(ctx, android.R.attr.selectableItemBackground) } if (doCheck) { + val instant = item.streamWithState.stream.uploadInstant // If the uploadDate is null or true we should highlight the item - if (item.streamWithState.stream.uploadDate?.isAfter(updateTime) != false) { + if (instant != null && instant > updateTime) { highlightCount++ typeface = Typeface.DEFAULT_BOLD diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedState.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedState.kt index 665ebbe43..da0fd3c13 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedState.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedState.kt @@ -2,7 +2,7 @@ package org.schabi.newpipe.local.feed import androidx.annotation.StringRes import org.schabi.newpipe.local.feed.item.StreamItem -import java.time.OffsetDateTime +import java.time.Instant sealed class FeedState { data class ProgressState( @@ -13,7 +13,7 @@ sealed class FeedState { data class LoadedState( val items: List, - val oldestUpdate: OffsetDateTime?, + val oldestUpdate: Instant?, val notLoadedCount: Long, val itemsErrors: List ) : FeedState() diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 728570b17..c22a245aa 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -25,7 +25,7 @@ import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent import org.schabi.newpipe.util.DEFAULT_THROTTLE_TIMEOUT -import java.time.OffsetDateTime +import java.time.Instant import java.util.concurrent.TimeUnit class FeedViewModel( @@ -61,11 +61,11 @@ class FeedViewModel( showPlayedItemsFlowable, showPartiallyPlayedItemsFlowable, showFutureItemsFlowable, - feedDatabaseManager.notLoadedCount(groupId), + feedDatabaseManager.getNotLoadedCount(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId), Function6 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, t4: Boolean, - t5: Long, t6: List -> + t5: Long, t6: List -> return@Function6 CombineResultEventHolder(t1, t2, t3, t4, t5, t6.firstOrNull()) } ) @@ -109,14 +109,14 @@ class FeedViewModel( val t3: Boolean, val t4: Boolean, val t5: Long, - val t6: OffsetDateTime? + val t6: Instant? ) private data class CombineResultDataHolder( val t1: FeedEventManager.Event, val t2: List, val t3: Long, - val t4: OffsetDateTime? + val t4: Instant? ) fun setSaveShowPlayedItems(showPlayedItems: Boolean) { diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt b/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt index 4a071d6df..790a25f16 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt @@ -137,9 +137,9 @@ data class StreamItem( } private fun getFormattedRelativeUploadDate(context: Context): String? { - val uploadDate = stream.uploadDate + val uploadDate = stream.uploadInstant return if (uploadDate != null) { - var formattedRelativeTime = Localization.relativeTime(uploadDate) + var formattedRelativeTime = Localization.formatRelativeTime(uploadDate) if (MainActivity.DEBUG) { val key = context.getString(R.string.show_original_time_ago_key) diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadManager.kt b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadManager.kt index 9b0f177d5..3aff7d87d 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadManager.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadManager.kt @@ -27,8 +27,9 @@ import org.schabi.newpipe.util.ChannelTabHelper import org.schabi.newpipe.util.ExtractorHelper.getChannelInfo import org.schabi.newpipe.util.ExtractorHelper.getChannelTab import org.schabi.newpipe.util.ExtractorHelper.getMoreChannelTabItems -import java.time.OffsetDateTime -import java.time.ZoneOffset +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger @@ -69,26 +70,26 @@ class FeedLoadManager(private val context: Context) { ) val outdatedThreshold = if (ignoreOutdatedThreshold) { - OffsetDateTime.now(ZoneOffset.UTC) + Instant.now() } else { val thresholdOutdatedSeconds = defaultSharedPreferences.getStringSafe( context.getString(R.string.feed_update_threshold_key), context.getString(R.string.feed_update_threshold_default_value) - ).toInt() - OffsetDateTime.now(ZoneOffset.UTC).minusSeconds(thresholdOutdatedSeconds.toLong()) + ).toLong() + Instant.now().minusSeconds(thresholdOutdatedSeconds) } /** * subscriptions which have not been updated within the feed updated threshold */ val outdatedSubscriptions = when (groupId) { - FeedGroupEntity.GROUP_ALL_ID -> feedDatabaseManager.outdatedSubscriptions( + FeedGroupEntity.GROUP_ALL_ID -> feedDatabaseManager.getOutdatedSubscriptions( outdatedThreshold ) - GROUP_NOTIFICATION_ENABLED -> feedDatabaseManager.outdatedSubscriptionsWithNotificationMode( + GROUP_NOTIFICATION_ENABLED -> feedDatabaseManager.getOutdatedSubscriptionsWithNotificationMode( outdatedThreshold, NotificationMode.ENABLED ) - else -> feedDatabaseManager.outdatedSubscriptionsForGroup(groupId, outdatedThreshold) + else -> feedDatabaseManager.getOutdatedSubscriptionsForGroup(groupId, outdatedThreshold) } // like `currentProgress`, but counts the number of YouTube extractions that have begun, so @@ -319,15 +320,14 @@ class FeedLoadManager(private val context: Context) { } private fun filterNewStreams(list: List): List { + val zoneId = ZoneId.systemDefault() return list.filter { + // Streams older than this date are automatically removed from the feed. + // Therefore, streams which are not in the database, + // but older than this date, are considered old. + val date = it.uploadDate?.let { LocalDate.ofInstant(it.instant, zoneId) } !feedDatabaseManager.doesStreamExist(it) && - it.uploadDate != null && - // Streams older than this date are automatically removed from the feed. - // Therefore, streams which are not in the database, - // but older than this date, are considered old. - it.uploadDate!!.offsetDateTime().isAfter( - FeedDatabaseManager.FEED_OLDEST_ALLOWED_DATE - ) + date != null && date > FeedDatabaseManager.FEED_OLDEST_ALLOWED_DATE } } } diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index ed3cf548f..624ab4e60 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -47,8 +47,7 @@ import org.schabi.newpipe.local.feed.FeedViewModel; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.util.ExtractorHelper; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -96,7 +95,7 @@ public class HistoryRecordManager { return Maybe.empty(); } - final OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC); + final var currentTime = Instant.now(); return Maybe.fromCallable(() -> database.runInTransaction(() -> { final long streamId; final long duration; @@ -139,14 +138,14 @@ public class HistoryRecordManager { return Maybe.empty(); } - final OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC); + final var currentTime = Instant.now(); return Maybe.fromCallable(() -> database.runInTransaction(() -> { final long streamId = streamTable.upsert(new StreamEntity(info)); final StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId); if (latestEntry != null) { streamHistoryTable.delete(latestEntry); - latestEntry.setAccessDate(currentTime); + latestEntry.setAccessInstant(currentTime); latestEntry.setRepeatCount(latestEntry.getRepeatCount() + 1); return streamHistoryTable.insert(latestEntry); } else { @@ -194,13 +193,13 @@ public class HistoryRecordManager { return Maybe.empty(); } - final OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC); + final var currentTime = Instant.now(); final SearchHistoryEntry newEntry = new SearchHistoryEntry(currentTime, serviceId, search); return Maybe.fromCallable(() -> database.runInTransaction(() -> { final SearchHistoryEntry latestEntry = searchHistoryTable.getLatestEntry(); if (latestEntry != null && latestEntry.hasEqualValues(newEntry)) { - latestEntry.setCreationDate(currentTime); + latestEntry.setCreationInstant(currentTime); return (long) searchHistoryTable.update(latestEntry); } else { return searchHistoryTable.insert(newEntry); diff --git a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java index 3302e387e..058aac291 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java @@ -69,7 +69,7 @@ public class StatisticsPlaylistFragment final Comparator comparator; switch (sortMode) { case LAST_PLAYED: - comparator = Comparator.comparing(StreamStatisticsEntry::getLatestAccessDate); + comparator = Comparator.comparing(StreamStatisticsEntry::getLatestAccessInstant); break; case MOST_PLAYED: comparator = Comparator.comparingLong(StreamStatisticsEntry::getWatchCount); diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java index 150a35eb5..2e1f09a9d 100644 --- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalStatisticStreamItemHolder.java @@ -74,7 +74,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder { return Localization.concatenateStrings( // watchCount Localization.shortViewCount(itemBuilder.getContext(), entry.getWatchCount()), - dateTimeFormatter.format(entry.getLatestAccessDate()), + dateTimeFormatter.format(entry.latestAccessInstant()), // serviceName ServiceHelper.getNameOfServiceById(entry.getStreamEntity().getServiceId())); } diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java index b8cc26b41..b8780c535 100644 --- a/app/src/main/java/org/schabi/newpipe/util/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java @@ -2,7 +2,6 @@ package org.schabi.newpipe.util; import static org.schabi.newpipe.MainActivity.DEBUG; -import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; @@ -34,7 +33,8 @@ import org.schabi.newpipe.extractor.stream.AudioTrackType; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.NumberFormat; -import java.time.OffsetDateTime; +import java.time.Instant; +import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; @@ -130,16 +130,11 @@ public final class Localization { return NumberFormat.getInstance(getAppLocale()).format(number); } - public static String formatDate(@NonNull final OffsetDateTime offsetDateTime) { - return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) - .withLocale(getAppLocale()) - .format(offsetDateTime.atZoneSameInstant(ZoneId.systemDefault())); - } - - @SuppressLint("StringFormatInvalid") - public static String localizeUploadDate(@NonNull final Context context, - @NonNull final OffsetDateTime offsetDateTime) { - return context.getString(R.string.upload_date_text, formatDate(offsetDateTime)); + @NonNull + public static String formatDate(@NonNull final DateWrapper dateWrapper) { + final var localDate = LocalDate.ofInstant(dateWrapper.getInstant(), ZoneId.systemDefault()); + return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(getAppLocale()) + .format(localDate); } public static String localizeViewCount(@NonNull final Context context, final long viewCount) { @@ -379,8 +374,8 @@ public final class Localization { return new PrettyTime(getAppLocale()); } - public static String relativeTime(@NonNull final OffsetDateTime offsetDateTime) { - return prettyTime.formatUnrounded(offsetDateTime); + public static String formatRelativeTime(@NonNull final Instant instant) { + return prettyTime.formatUnrounded(instant); } /** @@ -389,23 +384,23 @@ public final class Localization { * @param parsed the textual date or time ago parsed by NewPipeExtractor, or {@code null} if * the extractor could not parse it * @param textual the original textual date or time ago string as provided by services - * @return {@link #relativeTime(OffsetDateTime)} is used if {@code parsed != null}, otherwise + * @return {@link #formatRelativeTime(Instant)} is used if {@code parsed != null}, otherwise * {@code textual} is returned. If in debug mode, {@code context != null}, * {@code parsed != null} and the relevant setting is enabled, {@code textual} will * be appended to the returned string for debugging purposes. */ @Nullable - public static String relativeTimeOrTextual(@Nullable final Context context, - @Nullable final DateWrapper parsed, - @Nullable final String textual) { + public static String formatRelativeTimeOrTextual(@Nullable final Context context, + @Nullable final DateWrapper parsed, + @Nullable final String textual) { if (parsed == null) { return textual; } else if (DEBUG && context != null && PreferenceManager .getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.show_original_time_ago_key), false)) { - return relativeTime(parsed.offsetDateTime()) + " (" + textual + ")"; + return formatRelativeTime(parsed.getInstant()) + " (" + textual + ")"; } else { - return relativeTime(parsed.offsetDateTime()); + return formatRelativeTime(parsed.getInstant()); } } diff --git a/app/src/test/java/org/schabi/newpipe/util/LocalizationTest.kt b/app/src/test/java/org/schabi/newpipe/util/LocalizationTest.kt index ab6396951..f1f354f54 100644 --- a/app/src/test/java/org/schabi/newpipe/util/LocalizationTest.kt +++ b/app/src/test/java/org/schabi/newpipe/util/LocalizationTest.kt @@ -3,25 +3,29 @@ package org.schabi.newpipe.util import org.junit.Assert.assertEquals import org.junit.Test import org.ocpsoft.prettytime.PrettyTime +import java.time.Instant import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneOffset +import java.time.Month +import java.time.ZoneId import java.util.Locale class LocalizationTest { @Test(expected = NullPointerException::class) - fun `relativeTime() must fail without initializing pretty time`() { - Localization.relativeTime(OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC)) + fun `formatRelativeTime() must fail without initializing pretty time`() { + val instant = Instant.now() + Localization.formatRelativeTime(instant) } @Test - fun `relativeTime() with a OffsetDateTime must work`() { - val prettyTime = PrettyTime(LocalDate.of(2021, 1, 1), ZoneOffset.UTC) + fun `formatRelativeTime() with an Instant must work`() { + val zoneId = ZoneId.systemDefault() + val date = LocalDate.of(2021, Month.JANUARY, 1) + val prettyTime = PrettyTime(date, zoneId) prettyTime.locale = Locale.ENGLISH Localization.initPrettyTime(prettyTime) - val offset = OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC) - val actual = Localization.relativeTime(offset) + val instant = date.plusDays(5).atStartOfDay(zoneId).toInstant() + val actual = Localization.formatRelativeTime(instant) assertEquals("5 days from now", actual) }