Merge pull request #5230 from Isira-Seneviratne/Update_prettytime
Update prettytime.
This commit is contained in:
commit
4fac3cf304
|
@ -233,7 +233,7 @@ dependencies {
|
||||||
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
|
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
|
||||||
implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"
|
implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"
|
||||||
|
|
||||||
implementation "org.ocpsoft.prettytime:prettytime:4.0.6.Final"
|
implementation "org.ocpsoft.prettytime:prettytime:5.0.0.Final"
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.1'
|
testImplementation 'junit:junit:4.13.1'
|
||||||
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package org.schabi.newpipe.ktx
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import java.time.temporal.ChronoField
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.GregorianCalendar
|
|
||||||
import java.util.TimeZone
|
|
||||||
|
|
||||||
// This method is a modified version of GregorianCalendar.from(ZonedDateTime).
|
|
||||||
// Math.addExact() and Math.multiplyExact() are desugared even though lint displays a warning.
|
|
||||||
@SuppressWarnings("NewApi")
|
|
||||||
fun OffsetDateTime.toCalendar(): Calendar {
|
|
||||||
val cal = GregorianCalendar(TimeZone.getTimeZone("UTC"))
|
|
||||||
val offsetDateTimeUTC = withOffsetSameInstant(ZoneOffset.UTC)
|
|
||||||
cal.gregorianChange = Date(Long.MIN_VALUE)
|
|
||||||
cal.firstDayOfWeek = Calendar.MONDAY
|
|
||||||
cal.minimalDaysInFirstWeek = 4
|
|
||||||
try {
|
|
||||||
cal.timeInMillis = Math.addExact(
|
|
||||||
Math.multiplyExact(offsetDateTimeUTC.toEpochSecond(), 1000),
|
|
||||||
offsetDateTimeUTC[ChronoField.MILLI_OF_SECOND].toLong()
|
|
||||||
)
|
|
||||||
} catch (ex: ArithmeticException) {
|
|
||||||
throw IllegalArgumentException(ex)
|
|
||||||
}
|
|
||||||
return cal
|
|
||||||
}
|
|
|
@ -45,7 +45,7 @@ import org.schabi.newpipe.ktx.animate
|
||||||
import org.schabi.newpipe.ktx.animateHideRecyclerViewAllowingScrolling
|
import org.schabi.newpipe.ktx.animateHideRecyclerViewAllowingScrolling
|
||||||
import org.schabi.newpipe.local.feed.service.FeedLoadService
|
import org.schabi.newpipe.local.feed.service.FeedLoadService
|
||||||
import org.schabi.newpipe.util.Localization
|
import org.schabi.newpipe.util.Localization
|
||||||
import java.util.Calendar
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
class FeedFragment : BaseListFragment<FeedState, Unit>() {
|
class FeedFragment : BaseListFragment<FeedState, Unit>() {
|
||||||
private var _feedBinding: FragmentFeedBinding? = null
|
private var _feedBinding: FragmentFeedBinding? = null
|
||||||
|
@ -58,7 +58,7 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
|
||||||
|
|
||||||
private var groupId = FeedGroupEntity.GROUP_ALL_ID
|
private var groupId = FeedGroupEntity.GROUP_ALL_ID
|
||||||
private var groupName = ""
|
private var groupName = ""
|
||||||
private var oldestSubscriptionUpdate: Calendar? = null
|
private var oldestSubscriptionUpdate: OffsetDateTime? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
|
@ -275,12 +275,10 @@ class FeedFragment : BaseListFragment<FeedState, Unit>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRefreshViewState() {
|
private fun updateRefreshViewState() {
|
||||||
val oldestSubscriptionUpdateText = when {
|
feedBinding.refreshText.text = getString(
|
||||||
oldestSubscriptionUpdate != null -> Localization.relativeTime(oldestSubscriptionUpdate!!)
|
R.string.feed_oldest_subscription_update,
|
||||||
else -> "—"
|
oldestSubscriptionUpdate?.let { Localization.relativeTime(it) } ?: "—"
|
||||||
}
|
)
|
||||||
|
|
||||||
feedBinding.refreshText.text = getString(R.string.feed_oldest_subscription_update, oldestSubscriptionUpdateText)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.schabi.newpipe.local.feed
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
import java.util.Calendar
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
sealed class FeedState {
|
sealed class FeedState {
|
||||||
data class ProgressState(
|
data class ProgressState(
|
||||||
|
@ -13,7 +13,7 @@ sealed class FeedState {
|
||||||
|
|
||||||
data class LoadedState(
|
data class LoadedState(
|
||||||
val items: List<StreamInfoItem>,
|
val items: List<StreamInfoItem>,
|
||||||
val oldestUpdate: Calendar? = null,
|
val oldestUpdate: OffsetDateTime? = null,
|
||||||
val notLoadedCount: Long,
|
val notLoadedCount: Long,
|
||||||
val itemsErrors: List<Throwable> = emptyList()
|
val itemsErrors: List<Throwable> = emptyList()
|
||||||
) : FeedState()
|
) : FeedState()
|
||||||
|
|
|
@ -11,7 +11,6 @@ import io.reactivex.rxjava3.functions.Function4
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
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
|
||||||
|
@ -48,13 +47,11 @@ class FeedViewModel(applicationContext: Context, val groupId: Long = FeedGroupEn
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe { (event, listFromDB, notLoadedCount, oldestUpdate) ->
|
.subscribe { (event, listFromDB, notLoadedCount, oldestUpdate) ->
|
||||||
val oldestUpdateCalendar = oldestUpdate?.toCalendar()
|
|
||||||
|
|
||||||
mutableStateLiveData.postValue(
|
mutableStateLiveData.postValue(
|
||||||
when (event) {
|
when (event) {
|
||||||
is IdleEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount)
|
is IdleEvent -> FeedState.LoadedState(listFromDB, oldestUpdate, notLoadedCount)
|
||||||
is ProgressEvent -> FeedState.ProgressState(event.currentProgress, event.maxProgress, event.progressMessage)
|
is ProgressEvent -> FeedState.ProgressState(event.currentProgress, event.maxProgress, event.progressMessage)
|
||||||
is SuccessResultEvent -> FeedState.LoadedState(listFromDB, oldestUpdateCalendar, notLoadedCount, event.itemsErrors)
|
is SuccessResultEvent -> FeedState.LoadedState(listFromDB, oldestUpdate, notLoadedCount, event.itemsErrors)
|
||||||
is ErrorResultEvent -> FeedState.ErrorState(event.error)
|
is ErrorResultEvent -> FeedState.ErrorState(event.error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.ocpsoft.prettytime.units.Decade;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
import org.schabi.newpipe.ktx.OffsetDateTimeKt;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
@ -30,7 +29,6 @@ import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.FormatStyle;
|
import java.time.format.FormatStyle;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -314,11 +312,7 @@ public final class Localization {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String relativeTime(final OffsetDateTime offsetDateTime) {
|
public static String relativeTime(final OffsetDateTime offsetDateTime) {
|
||||||
return relativeTime(OffsetDateTimeKt.toCalendar(offsetDateTime));
|
return prettyTime.formatUnrounded(offsetDateTime);
|
||||||
}
|
|
||||||
|
|
||||||
public static String relativeTime(final Calendar calendarTime) {
|
|
||||||
return prettyTime.formatUnrounded(calendarTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void changeAppLanguage(final Locale loc, final Resources res) {
|
private static void changeAppLanguage(final Locale loc, final Resources res) {
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package org.schabi.newpipe.ktx
|
|
||||||
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Test
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.OffsetDateTime
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.TimeZone
|
|
||||||
|
|
||||||
class OffsetDateTimeToCalendarTest {
|
|
||||||
@Test
|
|
||||||
fun testRelativeTimeWithCurrentOffsetDateTime() {
|
|
||||||
val calendar = LocalDate.of(2020, 1, 1).atStartOfDay().atOffset(ZoneOffset.UTC)
|
|
||||||
.toCalendar()
|
|
||||||
|
|
||||||
assertEquals(2020, calendar[Calendar.YEAR])
|
|
||||||
assertEquals(0, calendar[Calendar.MONTH])
|
|
||||||
assertEquals(1, calendar[Calendar.DAY_OF_MONTH])
|
|
||||||
assertEquals(0, calendar[Calendar.HOUR])
|
|
||||||
assertEquals(0, calendar[Calendar.MINUTE])
|
|
||||||
assertEquals(0, calendar[Calendar.SECOND])
|
|
||||||
assertEquals(TimeZone.getTimeZone("UTC"), calendar.timeZone)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
|
||||||
fun testRelativeTimeWithFarOffOffsetDateTime() {
|
|
||||||
OffsetDateTime.MAX.minusYears(1).toCalendar()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,34 +3,22 @@ package org.schabi.newpipe.util
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.ocpsoft.prettytime.PrettyTime
|
import org.ocpsoft.prettytime.PrettyTime
|
||||||
import java.text.SimpleDateFormat
|
import java.time.LocalDate
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
import java.util.GregorianCalendar
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class LocalizationTest {
|
class LocalizationTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `After initializing pretty time relativeTime() with a Calendar must work`() {
|
|
||||||
val reference = SimpleDateFormat("yyyy/MM/dd").parse("2021/1/1")
|
|
||||||
Localization.initPrettyTime(PrettyTime(reference, Locale.ENGLISH))
|
|
||||||
|
|
||||||
val actual = Localization.relativeTime(GregorianCalendar(2021, 1, 6))
|
|
||||||
|
|
||||||
// yes this assertion is true, even if it should be 5 days, it works as it is. Future research required.
|
|
||||||
assertEquals("1 month from now", actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = NullPointerException::class)
|
@Test(expected = NullPointerException::class)
|
||||||
fun `relativeTime() must fail without initializing pretty time`() {
|
fun `relativeTime() must fail without initializing pretty time`() {
|
||||||
Localization.relativeTime(GregorianCalendar(2021, 1, 6))
|
Localization.relativeTime(OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `relativeTime() with a OffsetDateTime must work`() {
|
fun `relativeTime() with a OffsetDateTime must work`() {
|
||||||
val reference = SimpleDateFormat("yyyy/MM/dd").parse("2021/1/1")
|
val prettyTime = PrettyTime(LocalDate.of(2021, 1, 1), ZoneOffset.UTC)
|
||||||
Localization.initPrettyTime(PrettyTime(reference, Locale.ENGLISH))
|
prettyTime.locale = Locale.ENGLISH
|
||||||
|
Localization.initPrettyTime(prettyTime)
|
||||||
|
|
||||||
val offset = OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC)
|
val offset = OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC)
|
||||||
val actual = Localization.relativeTime(offset)
|
val actual = Localization.relativeTime(offset)
|
||||||
|
|
Loading…
Reference in New Issue