mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2025-10-03 09:49:21 +02:00
Refactor codebase to use Instant instead of OffsetDateTime
This commit is contained in:
parent
fd3f030d0b
commit
88b687f57b
25 changed files with 159 additions and 184 deletions
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<List<StreamWithState>>
|
||||
|
||||
/**
|
||||
|
@ -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<List<OffsetDateTime>>
|
||||
abstract fun getOldestSubscriptionUpdate(groupId: Long): Flowable<List<Instant>>
|
||||
|
||||
@Query("SELECT MIN(last_updated) FROM feed_last_updated")
|
||||
abstract fun oldestSubscriptionUpdateFromAll(): Flowable<List<OffsetDateTime>>
|
||||
abstract fun getOldestSubscriptionUpdateFromAll(): Flowable<List<Instant>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL")
|
||||
abstract fun notLoadedCount(): Flowable<Long>
|
||||
abstract fun getNotLoadedCount(): Flowable<Long>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
|
@ -189,7 +189,7 @@ abstract class FeedDAO {
|
|||
WHERE lu.last_updated IS NULL
|
||||
"""
|
||||
)
|
||||
abstract fun notLoadedCountForGroup(groupId: Long): Flowable<Long>
|
||||
abstract fun getNotLoadedCountForGroup(groupId: Long): Flowable<Long>
|
||||
|
||||
@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<List<SubscriptionEntity>>
|
||||
abstract fun getAllOutdated(outdatedThreshold: Instant): Flowable<List<SubscriptionEntity>>
|
||||
|
||||
@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<List<SubscriptionEntity>>
|
||||
abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: Instant): Flowable<List<SubscriptionEntity>>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
|
@ -231,7 +231,7 @@ abstract class FeedDAO {
|
|||
"""
|
||||
)
|
||||
abstract fun getOutdatedWithNotificationMode(
|
||||
outdatedThreshold: OffsetDateTime,
|
||||
outdatedThreshold: Instant,
|
||||
@NotificationMode notificationMode: Int
|
||||
): Flowable<List<SubscriptionEntity>>
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<StreamEntity> {
|
||||
|
@ -95,9 +95,9 @@ abstract class StreamDAO : BasicDAO<StreamEntity> {
|
|||
// 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<StreamEntity> {
|
|||
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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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<Long> {
|
||||
fun getNotLoadedCount(groupId: Long = FeedGroupEntity.GROUP_ALL_ID): Flowable<Long> {
|
||||
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<StreamInfoItem>,
|
||||
oldestAllowedDate: OffsetDateTime = FEED_OLDEST_ALLOWED_DATE
|
||||
oldestAllowedDate: LocalDate = FEED_OLDEST_ALLOWED_DATE
|
||||
) {
|
||||
val itemsToInsert = ArrayList<StreamInfoItem>()
|
||||
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<List<OffsetDateTime>> {
|
||||
fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<Instant>> {
|
||||
return when (groupId) {
|
||||
FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll()
|
||||
else -> feedTable.oldestSubscriptionUpdate(groupId)
|
||||
FeedGroupEntity.GROUP_ALL_ID -> feedTable.getOldestSubscriptionUpdateFromAll()
|
||||
else -> feedTable.getOldestSubscriptionUpdate(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<FeedState>() {
|
||||
|
@ -95,7 +95,7 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
|||
|
||||
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<FeedState>() {
|
|||
val oldOldestSubscriptionUpdate = oldestSubscriptionUpdate
|
||||
|
||||
groupAdapter.updateAsync(loadedState.items, false) {
|
||||
oldOldestSubscriptionUpdate?.run {
|
||||
highlightNewItemsAfter(oldOldestSubscriptionUpdate)
|
||||
oldOldestSubscriptionUpdate?.let {
|
||||
highlightNewItemsAfter(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,14 +543,14 @@ class FeedFragment : BaseStateFragment<FeedState>() {
|
|||
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<FeedState>() {
|
|||
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
|
||||
|
|
|
@ -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<StreamItem>,
|
||||
val oldestUpdate: OffsetDateTime?,
|
||||
val oldestUpdate: Instant?,
|
||||
val notLoadedCount: Long,
|
||||
val itemsErrors: List<Throwable>
|
||||
) : FeedState()
|
||||
|
|
|
@ -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<OffsetDateTime> ->
|
||||
t5: Long, t6: List<Instant> ->
|
||||
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<StreamWithState>,
|
||||
val t3: Long,
|
||||
val t4: OffsetDateTime?
|
||||
val t4: Instant?
|
||||
)
|
||||
|
||||
fun setSaveShowPlayedItems(showPlayedItems: Boolean) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<StreamInfoItem>): List<StreamInfoItem> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -69,7 +69,7 @@ public class StatisticsPlaylistFragment
|
|||
final Comparator<StreamStatisticsEntry> 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);
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue