From 160d77c8701d0e77c649b1317f3cd659e43d43fe Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 7 Oct 2019 20:24:08 +0300 Subject: [PATCH] Relative time improvements --- app/build.gradle | 2 +- .../activities/topic/TopicActivity.java | 1 - .../gr/thmmy/mthmmy/utils/DateTimeUtils.java | 61 ++++++---- .../mthmmy/utils/RelativeTimeTextView.java | 19 +--- .../thmmy/mthmmy/utils/DateTimeUtilsTest.java | 106 ++++++++++++++++++ .../parsing/ThmmyDateTimeParserTest.java | 2 +- 6 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java diff --git a/app/build.gradle b/app/build.gradle index c9fd8891..bc9259a0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,7 +78,7 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-alpha04' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-alpha05' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.exifinterface:exifinterface:1.1.0-beta01' implementation 'com.google.android.material:material:1.0.0' diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index b5349d0b..2a9defb9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -5,7 +5,6 @@ import android.app.NotificationManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Rect; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java index 7802f931..a758769d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java @@ -1,5 +1,7 @@ package gr.thmmy.mthmmy.utils; +import androidx.annotation.VisibleForTesting; + import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -20,38 +22,55 @@ public class DateTimeUtils { return dateTime; } - private static final long MONTH_IN_MILLIS = DAY_IN_MILLIS*30; - private static final long DECADE_IN_MILLIS = YEAR_IN_MILLIS*10; + private static final long MONTH_IN_MILLIS = 30*DAY_IN_MILLIS; + private static final long DECADE_IN_MILLIS = 10*YEAR_IN_MILLIS; + + @VisibleForTesting + static String getRelativeTimeSpanString(long time) { + long now = System.currentTimeMillis(); - static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) { boolean past = (now >= time); long duration = Math.abs(now - time); String format; - long count; - if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { - count = duration / SECOND_IN_MILLIS; - format = "%d sec"; - } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { - count = duration / MINUTE_IN_MILLIS; - format = "%d min"; - } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { - count = duration / HOUR_IN_MILLIS; - format = "%d hour"; - if(count>1) - format = format + 's'; - } else if (duration < MONTH_IN_MILLIS && minResolution < MONTH_IN_MILLIS) { - count = duration / DAY_IN_MILLIS; + long count, mod; + if(duration < 45*SECOND_IN_MILLIS) + return "just now"; + else if (duration < 45*MINUTE_IN_MILLIS) { + count = duration/MINUTE_IN_MILLIS; + mod = duration % MINUTE_IN_MILLIS; + if(mod >= 30*SECOND_IN_MILLIS) + count += 1; + format = "%dm"; + } else if (duration < 22*HOUR_IN_MILLIS) { + count = duration/HOUR_IN_MILLIS; + format = "%dh"; + mod = (duration%HOUR_IN_MILLIS)/MINUTE_IN_MILLIS; + if(count<4 && mod>10 && mod<50) + format = format + mod +"m"; + else if(mod >= 30) + count += 1; + } else if (duration < 26*DAY_IN_MILLIS) { + count = duration/DAY_IN_MILLIS; format = "%d day"; + mod = duration % DAY_IN_MILLIS; + if(mod >= 12*HOUR_IN_MILLIS) + count += 1; if(count>1) format = format + 's'; - } else if (duration < YEAR_IN_MILLIS && minResolution < YEAR_IN_MILLIS) { - count = duration / MONTH_IN_MILLIS; + } else if (duration < 320*DAY_IN_MILLIS) { + count = duration/MONTH_IN_MILLIS; format = "%d month"; + mod = duration % MONTH_IN_MILLIS; + if(mod >= 15*DAY_IN_MILLIS) + count += 1; if(count>1) format = format + 's'; - } else if (duration < DECADE_IN_MILLIS && minResolution < DECADE_IN_MILLIS) { - count = duration / YEAR_IN_MILLIS; + } else if (duration < DECADE_IN_MILLIS) { + count = duration/YEAR_IN_MILLIS; format = "%d year"; + mod = duration % YEAR_IN_MILLIS; + if(mod >= 183*DAY_IN_MILLIS) + count += 1; if(count>1) format = format + 's'; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java b/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java index 083408c4..9b5b5f74 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/RelativeTimeTextView.java @@ -100,24 +100,7 @@ public class RelativeTimeTextView extends TextView { */ if (this.mReferenceTime == -1L) return; - setText(getRelativeTimeDisplayString(mReferenceTime, System.currentTimeMillis())); - } - - /** - * Get the text to display for relative time. - *
- * @param referenceTime The reference time passed in through {@link #setReferenceTime(long)} or through {@code reference_time} attribute - * @param now The current time - * @return The display text for the relative time - */ - protected CharSequence getRelativeTimeDisplayString(long referenceTime, long now) { - long difference = now - referenceTime; - return (difference >= 0 && difference<=DateUtils.MINUTE_IN_MILLIS) ? - "just now" : - getRelativeTimeSpanString( - mReferenceTime, - now, - DateUtils.MINUTE_IN_MILLIS); + setText(getRelativeTimeSpanString(mReferenceTime)); } @Override diff --git a/app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java b/app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java new file mode 100644 index 00000000..1a3eaa2b --- /dev/null +++ b/app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java @@ -0,0 +1,106 @@ +package gr.thmmy.mthmmy.utils; + +import net.lachlanmckee.timberjunit.TimberTestRule; + +import org.joda.time.DateTime; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString; +import static org.junit.Assert.assertArrayEquals; +import static org.mockito.Mockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(DateTimeUtils.class) +public class DateTimeUtilsTest { + @Rule + public TimberTestRule logAllAlwaysRule = TimberTestRule.logAllAlways(); + + private final long NOW = System.currentTimeMillis(); + private final String [] expectedRelativeTimeSpans = { + "just now", + "just now", + "just now", + "1m", + "1m", + "1m", + "2m", + "3m", + "1h", + "1h15m", + "2h", + "3h20m", + "4h", + "20h", + "21h", + "21h", + "21h", + "22h", + "1 day", + "1 day", + "2 days", + "2 days", + "3 days", + "16 days", + "1 month", + "2 months", + "1 year", + "1 year", + "2 years", + "a long time ago" + }; + + private final long [] times = { + NOW, + newDT().minusSeconds(44).getMillis(), + newDT().minusSeconds(44).minusMillis(500).getMillis(), + newDT().minusSeconds(45).getMillis(), + newDT().minusSeconds(89).getMillis(), + newDT().minusSeconds(89).minusMillis(500).getMillis(), + newDT().minusSeconds(90).getMillis(), + newDT().minusMinutes(3).minusSeconds(10).getMillis(), + newDT().minusHours(1).minusMinutes(4).getMillis(), + newDT().minusHours(1).minusMinutes(15).getMillis(), + newDT().minusHours(2).minusMinutes(4).getMillis(), + newDT().minusHours(3).minusMinutes(20).getMillis(), + newDT().minusHours(3).minusMinutes(51).getMillis(), + newDT().minusHours(20).minusMinutes(10).getMillis(), + newDT().minusHours(20).minusMinutes(30).getMillis(), + newDT().minusHours(21).getMillis(), + newDT().minusHours(21).minusMinutes(29).getMillis(), + newDT().minusHours(21).minusMinutes(30).getMillis(), + newDT().minusHours(22).minusMinutes(30).getMillis(), + newDT().minusHours(34).getMillis(), + newDT().minusHours(38).getMillis(), + newDT().minusDays(2).minusHours(10).getMillis(), + newDT().minusDays(2).minusHours(17).getMillis(), + newDT().minusDays(16).getMillis(), + newDT().minusDays(30+12).getMillis(), + newDT().minusDays(2*30+14).getMillis(), + newDT().minusDays(14*30).getMillis(), + newDT().minusMonths(15).getMillis(), + newDT().minusMonths(22).getMillis(), + newDT().minusYears(22).getMillis() + }; + + private DateTime newDT(){ + return new DateTime(NOW); + } + + @Test + public void relativeTimeSpansAreConvertedCorrectly() { + PowerMockito.mockStatic(System.class); + when(System.currentTimeMillis()).thenReturn(NOW); + + String[] timeStrings = new String[times.length]; + + for(int i=0; i