Merge pull request #4556 from Isira-Seneviratne/Switch_to_Java_8_Date_Time_API

Switch to the Java 8 Date/Time API.
This commit is contained in:
Stypox 2020-11-05 13:02:04 +01:00 committed by GitHub
commit 6f132f3fed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 122 additions and 109 deletions

View file

@ -5,31 +5,35 @@ import androidx.room.TypeConverter;
import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.local.subscription.FeedGroupIcon; import org.schabi.newpipe.local.subscription.FeedGroupIcon;
import java.util.Date; import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
public final class Converters { public final class Converters {
private Converters() { } private Converters() { }
/** /**
* Convert a long value to a date. * Convert a long value to a {@link OffsetDateTime}.
* *
* @param value the long value * @param value the long value
* @return the date * @return the {@code OffsetDateTime}
*/ */
@TypeConverter @TypeConverter
public static Date fromTimestamp(final Long value) { public static OffsetDateTime offsetDateTimeFromTimestamp(final Long value) {
return value == null ? null : new Date(value); return value == null ? null : OffsetDateTime.ofInstant(Instant.ofEpochMilli(value),
ZoneOffset.UTC);
} }
/** /**
* Convert a date to a long value. * Convert a {@link OffsetDateTime} to a long value.
* *
* @param date the date * @param offsetDateTime the {@code OffsetDateTime}
* @return the long value * @return the long value
*/ */
@TypeConverter @TypeConverter
public static Long dateToTimestamp(final Date date) { public static Long offsetDateTimeToTimestamp(final OffsetDateTime offsetDateTime) {
return date == null ? null : date.getTime(); return offsetDateTime == null ? null : offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC)
.toInstant().toEpochMilli();
} }
@TypeConverter @TypeConverter

View file

@ -7,7 +7,7 @@ import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Update import androidx.room.Update
import io.reactivex.Flowable import io.reactivex.Flowable
import java.util.Date import java.time.OffsetDateTime
import org.schabi.newpipe.database.feed.model.FeedEntity import org.schabi.newpipe.database.feed.model.FeedEntity
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
@ -58,10 +58,10 @@ abstract class FeedDAO {
INNER JOIN feed f INNER JOIN feed f
ON s.uid = f.stream_id ON s.uid = f.stream_id
WHERE s.upload_date < :date WHERE s.upload_date < :offsetDateTime
) )
""") """)
abstract fun unlinkStreamsOlderThan(date: Date) abstract fun unlinkStreamsOlderThan(offsetDateTime: OffsetDateTime)
@Query(""" @Query("""
DELETE FROM feed DELETE FROM feed
@ -106,10 +106,10 @@ abstract class FeedDAO {
INNER JOIN feed_group_subscription_join fgs INNER JOIN feed_group_subscription_join fgs
ON fgs.subscription_id = lu.subscription_id AND fgs.group_id = :groupId ON fgs.subscription_id = lu.subscription_id AND fgs.group_id = :groupId
""") """)
abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<Date>> abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<OffsetDateTime>>
@Query("SELECT MIN(last_updated) FROM feed_last_updated") @Query("SELECT MIN(last_updated) FROM feed_last_updated")
abstract fun oldestSubscriptionUpdateFromAll(): Flowable<List<Date>> abstract fun oldestSubscriptionUpdateFromAll(): Flowable<List<OffsetDateTime>>
@Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL") @Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL")
abstract fun notLoadedCount(): Flowable<Long> abstract fun notLoadedCount(): Flowable<Long>
@ -135,7 +135,7 @@ abstract class FeedDAO {
WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold
""") """)
abstract fun getAllOutdated(outdatedThreshold: Date): Flowable<List<SubscriptionEntity>> abstract fun getAllOutdated(outdatedThreshold: OffsetDateTime): Flowable<List<SubscriptionEntity>>
@Query(""" @Query("""
SELECT s.* FROM subscriptions s SELECT s.* FROM subscriptions s
@ -148,5 +148,5 @@ abstract class FeedDAO {
WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold WHERE lu.last_updated IS NULL OR lu.last_updated < :outdatedThreshold
""") """)
abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: Date): Flowable<List<SubscriptionEntity>> abstract fun getAllOutdatedForGroup(groupId: Long, outdatedThreshold: OffsetDateTime): Flowable<List<SubscriptionEntity>>
} }

View file

@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.Date import java.time.OffsetDateTime
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE 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.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
@ -25,9 +25,8 @@ data class FeedLastUpdatedEntity(
var subscriptionId: Long, var subscriptionId: Long,
@ColumnInfo(name = LAST_UPDATED) @ColumnInfo(name = LAST_UPDATED)
var lastUpdated: Date? = null var lastUpdated: OffsetDateTime? = null
) { ) {
companion object { companion object {
const val FEED_LAST_UPDATED_TABLE = "feed_last_updated" const val FEED_LAST_UPDATED_TABLE = "feed_last_updated"

View file

@ -6,7 +6,7 @@ import androidx.room.Ignore;
import androidx.room.Index; import androidx.room.Index;
import androidx.room.PrimaryKey; import androidx.room.PrimaryKey;
import java.util.Date; import java.time.OffsetDateTime;
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH; import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
@ -24,7 +24,7 @@ public class SearchHistoryEntry {
private long id; private long id;
@ColumnInfo(name = CREATION_DATE) @ColumnInfo(name = CREATION_DATE)
private Date creationDate; private OffsetDateTime creationDate;
@ColumnInfo(name = SERVICE_ID) @ColumnInfo(name = SERVICE_ID)
private int serviceId; private int serviceId;
@ -32,7 +32,8 @@ public class SearchHistoryEntry {
@ColumnInfo(name = SEARCH) @ColumnInfo(name = SEARCH)
private String search; private String search;
public SearchHistoryEntry(final Date creationDate, final int serviceId, final String search) { public SearchHistoryEntry(final OffsetDateTime creationDate, final int serviceId,
final String search) {
this.serviceId = serviceId; this.serviceId = serviceId;
this.creationDate = creationDate; this.creationDate = creationDate;
this.search = search; this.search = search;
@ -46,11 +47,11 @@ public class SearchHistoryEntry {
this.id = id; this.id = id;
} }
public Date getCreationDate() { public OffsetDateTime getCreationDate() {
return creationDate; return creationDate;
} }
public void setCreationDate(final Date creationDate) { public void setCreationDate(final OffsetDateTime creationDate) {
this.creationDate = creationDate; this.creationDate = creationDate;
} }

View file

@ -9,7 +9,7 @@ import androidx.room.Index;
import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamEntity;
import java.util.Date; import java.time.OffsetDateTime;
import static androidx.room.ForeignKey.CASCADE; import static androidx.room.ForeignKey.CASCADE;
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID; import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
@ -37,12 +37,12 @@ public class StreamHistoryEntity {
@NonNull @NonNull
@ColumnInfo(name = STREAM_ACCESS_DATE) @ColumnInfo(name = STREAM_ACCESS_DATE)
private Date accessDate; private OffsetDateTime accessDate;
@ColumnInfo(name = STREAM_REPEAT_COUNT) @ColumnInfo(name = STREAM_REPEAT_COUNT)
private long repeatCount; private long repeatCount;
public StreamHistoryEntity(final long streamUid, @NonNull final Date accessDate, public StreamHistoryEntity(final long streamUid, @NonNull final OffsetDateTime accessDate,
final long repeatCount) { final long repeatCount) {
this.streamUid = streamUid; this.streamUid = streamUid;
this.accessDate = accessDate; this.accessDate = accessDate;
@ -50,7 +50,7 @@ public class StreamHistoryEntity {
} }
@Ignore @Ignore
public StreamHistoryEntity(final long streamUid, @NonNull final Date accessDate) { public StreamHistoryEntity(final long streamUid, @NonNull final OffsetDateTime accessDate) {
this(streamUid, accessDate, 1); this(streamUid, accessDate, 1);
} }
@ -62,11 +62,12 @@ public class StreamHistoryEntity {
this.streamUid = streamUid; this.streamUid = streamUid;
} }
public Date getAccessDate() { @NonNull
public OffsetDateTime getAccessDate() {
return accessDate; return accessDate;
} }
public void setAccessDate(@NonNull final Date accessDate) { public void setAccessDate(@NonNull final OffsetDateTime accessDate) {
this.accessDate = accessDate; this.accessDate = accessDate;
} }

View file

@ -2,7 +2,7 @@ package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Embedded import androidx.room.Embedded
import java.util.Date import java.time.OffsetDateTime
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
data class StreamHistoryEntry( data class StreamHistoryEntry(
@ -13,7 +13,7 @@ data class StreamHistoryEntry(
val streamId: Long, val streamId: Long,
@ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE) @ColumnInfo(name = StreamHistoryEntity.STREAM_ACCESS_DATE)
val accessDate: Date, val accessDate: OffsetDateTime,
@ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT) @ColumnInfo(name = StreamHistoryEntity.STREAM_REPEAT_COUNT)
val repeatCount: Long val repeatCount: Long
@ -25,6 +25,6 @@ data class StreamHistoryEntry(
fun hasEqualValues(other: StreamHistoryEntry): Boolean { fun hasEqualValues(other: StreamHistoryEntry): Boolean {
return this.streamEntity.uid == other.streamEntity.uid && streamId == other.streamId && return this.streamEntity.uid == other.streamEntity.uid && streamId == other.streamId &&
accessDate.compareTo(other.accessDate) == 0 accessDate.isEqual(other.accessDate)
} }
} }

View file

@ -2,26 +2,25 @@ package org.schabi.newpipe.database.stream
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Embedded import androidx.room.Embedded
import java.util.Date import java.time.OffsetDateTime
import org.schabi.newpipe.database.LocalItem import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.history.model.StreamHistoryEntity import org.schabi.newpipe.database.history.model.StreamHistoryEntity
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
class StreamStatisticsEntry( class StreamStatisticsEntry(
@Embedded @Embedded
val streamEntity: StreamEntity, val streamEntity: StreamEntity,
@ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID) @ColumnInfo(name = StreamHistoryEntity.JOIN_STREAM_ID)
val streamId: Long, val streamId: Long,
@ColumnInfo(name = STREAM_LATEST_DATE) @ColumnInfo(name = STREAM_LATEST_DATE)
val latestAccessDate: Date, val latestAccessDate: OffsetDateTime,
@ColumnInfo(name = STREAM_WATCH_COUNT) @ColumnInfo(name = STREAM_WATCH_COUNT)
val watchCount: Long val watchCount: Long
) : LocalItem { ) : LocalItem {
fun toStreamInfoItem(): StreamInfoItem { fun toStreamInfoItem(): StreamInfoItem {
val item = StreamInfoItem(streamEntity.serviceId, streamEntity.url, streamEntity.title, streamEntity.streamType) val item = StreamInfoItem(streamEntity.serviceId, streamEntity.url, streamEntity.title, streamEntity.streamType)
item.duration = streamEntity.duration item.duration = streamEntity.duration

View file

@ -7,7 +7,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import io.reactivex.Flowable import io.reactivex.Flowable
import java.util.Date import java.time.OffsetDateTime
import org.schabi.newpipe.database.BasicDAO import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID
@ -129,7 +129,7 @@ abstract class StreamDAO : BasicDAO<StreamEntity> {
var textualUploadDate: String? = null, var textualUploadDate: String? = null,
@ColumnInfo(name = StreamEntity.STREAM_UPLOAD_DATE) @ColumnInfo(name = StreamEntity.STREAM_UPLOAD_DATE)
var uploadDate: Date? = null, var uploadDate: OffsetDateTime? = null,
@ColumnInfo(name = StreamEntity.STREAM_IS_UPLOAD_DATE_APPROXIMATION) @ColumnInfo(name = StreamEntity.STREAM_IS_UPLOAD_DATE_APPROXIMATION)
var isUploadDateApproximation: Boolean? = null, var isUploadDateApproximation: Boolean? = null,

View file

@ -6,8 +6,7 @@ import androidx.room.Ignore
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.util.Calendar import java.time.OffsetDateTime
import java.util.Date
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_TABLE import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_TABLE
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_URL import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_URL
@ -55,18 +54,17 @@ data class StreamEntity(
var textualUploadDate: String? = null, var textualUploadDate: String? = null,
@ColumnInfo(name = STREAM_UPLOAD_DATE) @ColumnInfo(name = STREAM_UPLOAD_DATE)
var uploadDate: Date? = null, var uploadDate: OffsetDateTime? = null,
@ColumnInfo(name = STREAM_IS_UPLOAD_DATE_APPROXIMATION) @ColumnInfo(name = STREAM_IS_UPLOAD_DATE_APPROXIMATION)
var isUploadDateApproximation: Boolean? = null var isUploadDateApproximation: Boolean? = null
) : Serializable { ) : Serializable {
@Ignore @Ignore
constructor(item: StreamInfoItem) : this( constructor(item: StreamInfoItem) : this(
serviceId = item.serviceId, url = item.url, title = item.name, serviceId = item.serviceId, url = item.url, title = item.name,
streamType = item.streamType, duration = item.duration, uploader = item.uploaderName, streamType = item.streamType, duration = item.duration, uploader = item.uploaderName,
thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount, thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount,
textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.date()?.time, textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(),
isUploadDateApproximation = item.uploadDate?.isApproximation isUploadDateApproximation = item.uploadDate?.isApproximation
) )
@ -75,7 +73,7 @@ data class StreamEntity(
serviceId = info.serviceId, url = info.url, title = info.name, serviceId = info.serviceId, url = info.url, title = info.name,
streamType = info.streamType, duration = info.duration, uploader = info.uploaderName, streamType = info.streamType, duration = info.duration, uploader = info.uploaderName,
thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount, thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount,
textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.date()?.time, textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(),
isUploadDateApproximation = info.uploadDate?.isApproximation isUploadDateApproximation = info.uploadDate?.isApproximation
) )
@ -95,8 +93,7 @@ data class StreamEntity(
if (viewCount != null) item.viewCount = viewCount as Long if (viewCount != null) item.viewCount = viewCount as Long
item.textualUploadDate = textualUploadDate item.textualUploadDate = textualUploadDate
item.uploadDate = uploadDate?.let { item.uploadDate = uploadDate?.let {
DateWrapper(Calendar.getInstance().apply { time = it }, isUploadDateApproximation DateWrapper(it, isUploadDateApproximation ?: false)
?: false)
} }
return item return item

View file

@ -1527,7 +1527,7 @@ public class VideoDetailFragment
if (info.getUploadDate() != null) { if (info.getUploadDate() != null) {
videoUploadDateView.setText(Localization videoUploadDateView.setText(Localization
.localizeUploadDate(activity, info.getUploadDate().date().getTime())); .localizeUploadDate(activity, info.getUploadDate().offsetDateTime()));
videoUploadDateView.setVisibility(View.VISIBLE); videoUploadDateView.setVisibility(View.VISIBLE);
} else { } else {
videoUploadDateView.setText(null); videoUploadDateView.setText(null);

View file

@ -0,0 +1,10 @@
package org.schabi.newpipe.ktx
import java.time.OffsetDateTime
import java.time.ZoneId
import java.util.Calendar
import java.util.GregorianCalendar
fun OffsetDateTime.toCalendar(zoneId: ZoneId = ZoneId.systemDefault()): Calendar {
return GregorianCalendar.from(if (zoneId != offset) atZoneSameInstant(zoneId) else toZonedDateTime())
}

View file

@ -26,7 +26,8 @@ import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -69,7 +70,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
private final LocalItemBuilder localItemBuilder; private final LocalItemBuilder localItemBuilder;
private final ArrayList<LocalItem> localItems; private final ArrayList<LocalItem> localItems;
private final HistoryRecordManager recordManager; private final HistoryRecordManager recordManager;
private final DateFormat dateFormat; private final DateTimeFormatter dateTimeFormatter;
private boolean showFooter = false; private boolean showFooter = false;
private boolean useGridVariant = false; private boolean useGridVariant = false;
@ -80,8 +81,8 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
recordManager = new HistoryRecordManager(context); recordManager = new HistoryRecordManager(context);
localItemBuilder = new LocalItemBuilder(context); localItemBuilder = new LocalItemBuilder(context);
localItems = new ArrayList<>(); localItems = new ArrayList<>();
dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
Localization.getPreferredLocale(context)); .withLocale(Localization.getPreferredLocale(context));
} }
public void setSelectedListener(final OnClickGesture<LocalItem> listener) { public void setSelectedListener(final OnClickGesture<LocalItem> listener) {
@ -303,7 +304,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
} }
((LocalItemHolder) holder) ((LocalItemHolder) holder)
.updateFromItem(localItems.get(position), recordManager, dateFormat); .updateFromItem(localItems.get(position), recordManager, dateTimeFormatter);
} else if (holder instanceof HeaderFooterHolder && position == 0 && header != null) { } else if (holder instanceof HeaderFooterHolder && position == 0 && header != null) {
((HeaderFooterHolder) holder).view = header; ((HeaderFooterHolder) holder).view = header;
} else if (holder instanceof HeaderFooterHolder && position == sizeConsideringHeader() } else if (holder instanceof HeaderFooterHolder && position == sizeConsideringHeader()

View file

@ -7,8 +7,9 @@ import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.Calendar import java.time.LocalDate
import java.util.Date import java.time.OffsetDateTime
import java.time.ZoneOffset
import org.schabi.newpipe.MainActivity.DEBUG import org.schabi.newpipe.MainActivity.DEBUG
import org.schabi.newpipe.NewPipeDatabase import org.schabi.newpipe.NewPipeDatabase
import org.schabi.newpipe.database.feed.model.FeedEntity import org.schabi.newpipe.database.feed.model.FeedEntity
@ -29,13 +30,8 @@ class FeedDatabaseManager(context: Context) {
/** /**
* Only items that are newer than this will be saved. * Only items that are newer than this will be saved.
*/ */
val FEED_OLDEST_ALLOWED_DATE: Calendar = Calendar.getInstance().apply { val FEED_OLDEST_ALLOWED_DATE: OffsetDateTime = LocalDate.now().minusWeeks(13)
add(Calendar.WEEK_OF_YEAR, -13) .atStartOfDay().atOffset(ZoneOffset.UTC)
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
} }
fun groups() = feedGroupTable.getAll() fun groups() = feedGroupTable.getAll()
@ -55,7 +51,7 @@ class FeedDatabaseManager(context: Context) {
} }
} }
fun outdatedSubscriptions(outdatedThreshold: Date) = feedTable.getAllOutdated(outdatedThreshold) fun outdatedSubscriptions(outdatedThreshold: OffsetDateTime) = feedTable.getAllOutdated(outdatedThreshold)
fun notLoadedCount(groupId: Long = FeedGroupEntity.GROUP_ALL_ID): Flowable<Long> { fun notLoadedCount(groupId: Long = FeedGroupEntity.GROUP_ALL_ID): Flowable<Long> {
return when (groupId) { return when (groupId) {
@ -64,7 +60,7 @@ class FeedDatabaseManager(context: Context) {
} }
} }
fun outdatedSubscriptionsForGroup(groupId: Long = FeedGroupEntity.GROUP_ALL_ID, outdatedThreshold: Date) = fun outdatedSubscriptionsForGroup(groupId: Long = FeedGroupEntity.GROUP_ALL_ID, outdatedThreshold: OffsetDateTime) =
feedTable.getAllOutdatedForGroup(groupId, outdatedThreshold) feedTable.getAllOutdatedForGroup(groupId, outdatedThreshold)
fun markAsOutdated(subscriptionId: Long) = feedTable fun markAsOutdated(subscriptionId: Long) = feedTable
@ -73,7 +69,7 @@ class FeedDatabaseManager(context: Context) {
fun upsertAll( fun upsertAll(
subscriptionId: Long, subscriptionId: Long,
items: List<StreamInfoItem>, items: List<StreamInfoItem>,
oldestAllowedDate: Date = FEED_OLDEST_ALLOWED_DATE.time oldestAllowedDate: OffsetDateTime = FEED_OLDEST_ALLOWED_DATE
) { ) {
val itemsToInsert = ArrayList<StreamInfoItem>() val itemsToInsert = ArrayList<StreamInfoItem>()
loop@ for (streamItem in items) { loop@ for (streamItem in items) {
@ -81,7 +77,7 @@ class FeedDatabaseManager(context: Context) {
itemsToInsert += when { itemsToInsert += when {
uploadDate == null && streamItem.streamType == StreamType.LIVE_STREAM -> streamItem uploadDate == null && streamItem.streamType == StreamType.LIVE_STREAM -> streamItem
uploadDate != null && uploadDate.date().time >= oldestAllowedDate -> streamItem uploadDate != null && uploadDate.offsetDateTime() >= oldestAllowedDate -> streamItem
else -> continue@loop else -> continue@loop
} }
} }
@ -96,10 +92,11 @@ class FeedDatabaseManager(context: Context) {
feedTable.insertAll(feedEntities) feedTable.insertAll(feedEntities)
} }
feedTable.setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId, Calendar.getInstance().time)) feedTable.setLastUpdatedForSubscription(FeedLastUpdatedEntity(subscriptionId,
OffsetDateTime.now(ZoneOffset.UTC)))
} }
fun removeOrphansOrOlderStreams(oldestAllowedDate: Date = FEED_OLDEST_ALLOWED_DATE.time) { fun removeOrphansOrOlderStreams(oldestAllowedDate: OffsetDateTime = FEED_OLDEST_ALLOWED_DATE) {
feedTable.unlinkStreamsOlderThan(oldestAllowedDate) feedTable.unlinkStreamsOlderThan(oldestAllowedDate)
streamTable.deleteOrphans() streamTable.deleteOrphans()
} }
@ -159,7 +156,7 @@ class FeedDatabaseManager(context: Context) {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<Date>> { fun oldestSubscriptionUpdate(groupId: Long): Flowable<List<OffsetDateTime>> {
return when (groupId) { return when (groupId) {
FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll() FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll()
else -> feedTable.oldestSubscriptionUpdate(groupId) else -> feedTable.oldestSubscriptionUpdate(groupId)

View file

@ -9,11 +9,11 @@ import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function4 import io.reactivex.functions.Function4
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.Calendar import java.time.OffsetDateTime
import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import org.schabi.newpipe.database.feed.model.FeedGroupEntity import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.ktx.toCalendar
import org.schabi.newpipe.local.feed.service.FeedEventManager import org.schabi.newpipe.local.feed.service.FeedEventManager
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.IdleEvent
@ -41,7 +41,7 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn
feedDatabaseManager.notLoadedCount(groupId), feedDatabaseManager.notLoadedCount(groupId),
feedDatabaseManager.oldestSubscriptionUpdate(groupId), feedDatabaseManager.oldestSubscriptionUpdate(groupId),
Function4 { t1: FeedEventManager.Event, t2: List<StreamInfoItem>, t3: Long, t4: List<Date> -> Function4 { t1: FeedEventManager.Event, t2: List<StreamInfoItem>, t3: Long, t4: List<OffsetDateTime> ->
return@Function4 CombineResultHolder(t1, t2, t3, t4.firstOrNull()) return@Function4 CombineResultHolder(t1, t2, t3, t4.firstOrNull())
} }
) )
@ -51,8 +51,7 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn
.subscribe { .subscribe {
val (event, listFromDB, notLoadedCount, oldestUpdate) = it val (event, listFromDB, notLoadedCount, oldestUpdate) = it
val oldestUpdateCalendar = val oldestUpdateCalendar = oldestUpdate?.toCalendar()
oldestUpdate?.let { Calendar.getInstance().apply { time = it } }
mutableStateLiveData.postValue(when (event) { mutableStateLiveData.postValue(when (event) {
is IdleEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount) is IdleEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount)
@ -71,5 +70,5 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn
combineDisposable.dispose() combineDisposable.dispose()
} }
private data class CombineResultHolder(val t1: FeedEventManager.Event, val t2: List<StreamInfoItem>, val t3: Long, val t4: Date?) private data class CombineResultHolder(val t1: FeedEventManager.Event, val t2: List<StreamInfoItem>, val t3: Long, val t4: OffsetDateTime?)
} }

View file

@ -41,7 +41,8 @@ import io.reactivex.functions.Function
import io.reactivex.processors.PublishProcessor import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.io.IOException import java.io.IOException
import java.util.Calendar import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
@ -172,9 +173,7 @@ class FeedLoadService : Service() {
private fun startLoading(groupId: Long = FeedGroupEntity.GROUP_ALL_ID, useFeedExtractor: Boolean, thresholdOutdatedSeconds: Int) { private fun startLoading(groupId: Long = FeedGroupEntity.GROUP_ALL_ID, useFeedExtractor: Boolean, thresholdOutdatedSeconds: Int) {
feedResultsHolder = ResultsHolder() feedResultsHolder = ResultsHolder()
val outdatedThreshold = Calendar.getInstance().apply { val outdatedThreshold = OffsetDateTime.now(ZoneOffset.UTC).minusSeconds(thresholdOutdatedSeconds.toLong())
add(Calendar.SECOND, -thresholdOutdatedSeconds)
}.time
val subscriptions = when (groupId) { val subscriptions = when (groupId) {
FeedGroupEntity.GROUP_ALL_ID -> feedDatabaseManager.outdatedSubscriptions(outdatedThreshold) FeedGroupEntity.GROUP_ALL_ID -> feedDatabaseManager.outdatedSubscriptions(outdatedThreshold)

View file

@ -44,9 +44,10 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import io.reactivex.Completable; import io.reactivex.Completable;
@ -85,7 +86,7 @@ public class HistoryRecordManager {
return Maybe.empty(); return Maybe.empty();
} }
final Date currentTime = new Date(); final OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC);
return Maybe.fromCallable(() -> database.runInTransaction(() -> { return Maybe.fromCallable(() -> database.runInTransaction(() -> {
final long streamId = streamTable.upsert(new StreamEntity(info)); final long streamId = streamTable.upsert(new StreamEntity(info));
final StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId); final StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId);
@ -161,7 +162,7 @@ public class HistoryRecordManager {
return Maybe.empty(); return Maybe.empty();
} }
final Date currentTime = new Date(); final OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC);
final SearchHistoryEntry newEntry = new SearchHistoryEntry(currentTime, serviceId, search); final SearchHistoryEntry newEntry = new SearchHistoryEntry(currentTime, serviceId, search);
return Maybe.fromCallable(() -> database.runInTransaction(() -> { return Maybe.fromCallable(() -> database.runInTransaction(() -> {

View file

@ -9,7 +9,7 @@ import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
/* /*
* Created by Christian Schabesberger on 12.02.17. * Created by Christian Schabesberger on 12.02.17.
@ -41,7 +41,7 @@ public abstract class LocalItemHolder extends RecyclerView.ViewHolder {
} }
public abstract void updateFromItem(LocalItem item, HistoryRecordManager historyRecordManager, public abstract void updateFromItem(LocalItem item, HistoryRecordManager historyRecordManager,
DateFormat dateFormat); DateTimeFormatter dateTimeFormatter);
public void updateState(final LocalItem localItem, public void updateState(final LocalItem localItem,
final HistoryRecordManager historyRecordManager) { } final HistoryRecordManager historyRecordManager) { }

View file

@ -10,7 +10,7 @@ import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
public class LocalPlaylistItemHolder extends PlaylistItemHolder { public class LocalPlaylistItemHolder extends PlaylistItemHolder {
public LocalPlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final ViewGroup parent) { public LocalPlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final ViewGroup parent) {
@ -25,7 +25,7 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
@Override @Override
public void updateFromItem(final LocalItem localItem, public void updateFromItem(final LocalItem localItem,
final HistoryRecordManager historyRecordManager, final HistoryRecordManager historyRecordManager,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
if (!(localItem instanceof PlaylistMetadataEntry)) { if (!(localItem instanceof PlaylistMetadataEntry)) {
return; return;
} }
@ -39,6 +39,6 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView, itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS); ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
super.updateFromItem(localItem, historyRecordManager, dateFormat); super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
} }
} }

View file

@ -20,7 +20,7 @@ import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar; import org.schabi.newpipe.views.AnimatedProgressBar;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -52,7 +52,7 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
@Override @Override
public void updateFromItem(final LocalItem localItem, public void updateFromItem(final LocalItem localItem,
final HistoryRecordManager historyRecordManager, final HistoryRecordManager historyRecordManager,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
if (!(localItem instanceof PlaylistStreamEntry)) { if (!(localItem instanceof PlaylistStreamEntry)) {
return; return;
} }

View file

@ -20,7 +20,7 @@ import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.views.AnimatedProgressBar; import org.schabi.newpipe.views.AnimatedProgressBar;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -71,10 +71,10 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
} }
private String getStreamInfoDetailLine(final StreamStatisticsEntry entry, private String getStreamInfoDetailLine(final StreamStatisticsEntry entry,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
final String watchCount = Localization final String watchCount = Localization
.shortViewCount(itemBuilder.getContext(), entry.getWatchCount()); .shortViewCount(itemBuilder.getContext(), entry.getWatchCount());
final String uploadDate = dateFormat.format(entry.getLatestAccessDate()); final String uploadDate = dateTimeFormatter.format(entry.getLatestAccessDate());
final String serviceName = NewPipe.getNameOfService(entry.getStreamEntity().getServiceId()); final String serviceName = NewPipe.getNameOfService(entry.getStreamEntity().getServiceId());
return Localization.concatenateStrings(watchCount, uploadDate, serviceName); return Localization.concatenateStrings(watchCount, uploadDate, serviceName);
} }
@ -82,7 +82,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
@Override @Override
public void updateFromItem(final LocalItem localItem, public void updateFromItem(final LocalItem localItem,
final HistoryRecordManager historyRecordManager, final HistoryRecordManager historyRecordManager,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
if (!(localItem instanceof StreamStatisticsEntry)) { if (!(localItem instanceof StreamStatisticsEntry)) {
return; return;
} }
@ -116,7 +116,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
} }
if (itemAdditionalDetails != null) { if (itemAdditionalDetails != null) {
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat)); itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateTimeFormatter));
} }
// Default thumbnail is shown on error, while loading and if the url is empty // Default thumbnail is shown on error, while loading and if the url is empty

View file

@ -9,7 +9,7 @@ import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.local.LocalItemBuilder; import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
public abstract class PlaylistItemHolder extends LocalItemHolder { public abstract class PlaylistItemHolder extends LocalItemHolder {
public final ImageView itemThumbnailView; public final ImageView itemThumbnailView;
@ -34,7 +34,7 @@ public abstract class PlaylistItemHolder extends LocalItemHolder {
@Override @Override
public void updateFromItem(final LocalItem localItem, public void updateFromItem(final LocalItem localItem,
final HistoryRecordManager historyRecordManager, final HistoryRecordManager historyRecordManager,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
itemView.setOnClickListener(view -> { itemView.setOnClickListener(view -> {
if (itemBuilder.getOnItemSelectedListener() != null) { if (itemBuilder.getOnItemSelectedListener() != null) {
itemBuilder.getOnItemSelectedListener().selected(localItem); itemBuilder.getOnItemSelectedListener().selected(localItem);

View file

@ -11,7 +11,7 @@ import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import java.text.DateFormat; import java.time.format.DateTimeFormatter;
public class RemotePlaylistItemHolder extends PlaylistItemHolder { public class RemotePlaylistItemHolder extends PlaylistItemHolder {
public RemotePlaylistItemHolder(final LocalItemBuilder infoItemBuilder, public RemotePlaylistItemHolder(final LocalItemBuilder infoItemBuilder,
@ -27,7 +27,7 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
@Override @Override
public void updateFromItem(final LocalItem localItem, public void updateFromItem(final LocalItem localItem,
final HistoryRecordManager historyRecordManager, final HistoryRecordManager historyRecordManager,
final DateFormat dateFormat) { final DateTimeFormatter dateTimeFormatter) {
if (!(localItem instanceof PlaylistRemoteEntity)) { if (!(localItem instanceof PlaylistRemoteEntity)) {
return; return;
} }
@ -48,6 +48,6 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
itemBuilder.displayImage(item.getThumbnailUrl(), itemThumbnailView, itemBuilder.displayImage(item.getThumbnailUrl(), itemThumbnailView,
ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS); ImageDisplayConstants.DISPLAY_PLAYLIST_OPTIONS);
super.updateFromItem(localItem, historyRecordManager, dateFormat); super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
} }
} }

View file

@ -23,11 +23,13 @@ import org.schabi.newpipe.extractor.localization.ContentCountry;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -139,13 +141,16 @@ public final class Localization {
return nf.format(number); return nf.format(number);
} }
public static String formatDate(final Date date, final Context context) { public static String formatDate(final OffsetDateTime offsetDateTime, final Context context) {
return DateFormat.getDateInstance(DateFormat.MEDIUM, getAppLocale(context)).format(date); return DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(getAppLocale(context)).format(offsetDateTime
.atZoneSameInstant(ZoneId.systemDefault()));
} }
@SuppressLint("StringFormatInvalid") @SuppressLint("StringFormatInvalid")
public static String localizeUploadDate(final Context context, final Date date) { public static String localizeUploadDate(final Context context,
return context.getString(R.string.upload_date_text, formatDate(date, context)); final OffsetDateTime offsetDateTime) {
return context.getString(R.string.upload_date_text, formatDate(offsetDateTime, context));
} }
public static String localizeViewCount(final Context context, final long viewCount) { public static String localizeViewCount(final Context context, final long viewCount) {

View file

@ -5,7 +5,7 @@
<suppressions> <suppressions>
<suppress checks="FinalParameters" <suppress checks="FinalParameters"
files="LocalItemListAdapter.java" files="LocalItemListAdapter.java"
lines="220,292"/> lines="221,293"/>
<suppress checks="FinalParameters" <suppress checks="FinalParameters"
files="InfoListAdapter.java" files="InfoListAdapter.java"