mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-11-04 17:16:24 +00:00
Merge pull request #5358 from XiangRongLin/testable_prettytime
Make Localization.relativeTime testable
This commit is contained in:
commit
0264383ad2
@ -6,16 +6,26 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.multidex.MultiDexApplication;
|
import androidx.multidex.MultiDexApplication;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
|
import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.exceptions.CompositeException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.MissingBackpressureException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.UndeliverableException;
|
||||||
|
import io.reactivex.rxjava3.functions.Consumer;
|
||||||
|
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
import org.acra.config.ACRAConfigurationException;
|
import org.acra.config.ACRAConfigurationException;
|
||||||
import org.acra.config.CoreConfiguration;
|
import org.acra.config.CoreConfiguration;
|
||||||
@ -31,21 +41,6 @@ import org.schabi.newpipe.util.Localization;
|
|||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.exceptions.CompositeException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.MissingBackpressureException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.UndeliverableException;
|
|
||||||
import io.reactivex.rxjava3.functions.Consumer;
|
|
||||||
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
|
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
|
||||||
* App.java is part of NewPipe.
|
* App.java is part of NewPipe.
|
||||||
@ -95,7 +90,7 @@ public class App extends MultiDexApplication {
|
|||||||
NewPipe.init(getDownloader(),
|
NewPipe.init(getDownloader(),
|
||||||
Localization.getPreferredLocalization(this),
|
Localization.getPreferredLocalization(this),
|
||||||
Localization.getPreferredContentCountry(this));
|
Localization.getPreferredContentCountry(this));
|
||||||
Localization.init(getApplicationContext());
|
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
|
||||||
|
|
||||||
StateSaver.init(this);
|
StateSaver.init(this);
|
||||||
initNotificationChannels();
|
initNotificationChannels();
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -41,7 +43,6 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||||
@ -52,9 +53,10 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import org.schabi.newpipe.databinding.ActivityMainBinding;
|
import org.schabi.newpipe.databinding.ActivityMainBinding;
|
||||||
import org.schabi.newpipe.databinding.DrawerHeaderBinding;
|
import org.schabi.newpipe.databinding.DrawerHeaderBinding;
|
||||||
import org.schabi.newpipe.databinding.DrawerLayoutBinding;
|
import org.schabi.newpipe.databinding.DrawerLayoutBinding;
|
||||||
@ -87,12 +89,6 @@ import org.schabi.newpipe.util.TLSSocketFactoryCompat;
|
|||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import org.schabi.newpipe.views.FocusOverlayView;
|
import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
@ -468,7 +464,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
assureCorrectAppLanguage(this);
|
assureCorrectAppLanguage(this);
|
||||||
// Change the date format to match the selected language on resume
|
// Change the date format to match the selected language on resume
|
||||||
Localization.init(getApplicationContext());
|
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
// Close drawer on return, and don't show animation,
|
// Close drawer on return, and don't show animation,
|
||||||
|
@ -9,19 +9,10 @@ import android.icu.text.CompactDecimalFormat;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.PluralsRes;
|
import androidx.annotation.PluralsRes;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.ocpsoft.prettytime.PrettyTime;
|
|
||||||
import org.ocpsoft.prettytime.units.Decade;
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
|
||||||
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;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
@ -33,6 +24,12 @@ import java.util.Arrays;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import org.ocpsoft.prettytime.PrettyTime;
|
||||||
|
import org.ocpsoft.prettytime.units.Decade;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
|
import org.schabi.newpipe.ktx.OffsetDateTimeKt;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -62,10 +59,6 @@ public final class Localization {
|
|||||||
|
|
||||||
private Localization() { }
|
private Localization() { }
|
||||||
|
|
||||||
public static void init(final Context context) {
|
|
||||||
initPrettyTime(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String concatenateStrings(final String... strings) {
|
public static String concatenateStrings(final String... strings) {
|
||||||
return concatenateStrings(Arrays.asList(strings));
|
return concatenateStrings(Arrays.asList(strings));
|
||||||
@ -307,12 +300,16 @@ public final class Localization {
|
|||||||
// Pretty Time
|
// Pretty Time
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private static void initPrettyTime(final Context context) {
|
public static void initPrettyTime(final PrettyTime time) {
|
||||||
prettyTime = new PrettyTime(getAppLocale(context));
|
prettyTime = time;
|
||||||
// Do not use decades as YouTube doesn't either.
|
// Do not use decades as YouTube doesn't either.
|
||||||
prettyTime.removeUnit(Decade.class);
|
prettyTime.removeUnit(Decade.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PrettyTime resolvePrettyTime(final Context context) {
|
||||||
|
return new PrettyTime(getAppLocale(context));
|
||||||
|
}
|
||||||
|
|
||||||
public static String relativeTime(final OffsetDateTime offsetDateTime) {
|
public static String relativeTime(final OffsetDateTime offsetDateTime) {
|
||||||
return relativeTime(OffsetDateTimeKt.toCalendar(offsetDateTime));
|
return relativeTime(OffsetDateTimeKt.toCalendar(offsetDateTime));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package org.schabi.newpipe.util
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.ocpsoft.prettytime.PrettyTime
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
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)
|
||||||
|
fun `relativeTime() must fail without initializing pretty time`() {
|
||||||
|
Localization.relativeTime(GregorianCalendar(2021, 1, 6))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `relativeTime() with a OffsetDateTime must work`() {
|
||||||
|
val reference = SimpleDateFormat("yyyy/MM/dd").parse("2021/1/1")
|
||||||
|
Localization.initPrettyTime(PrettyTime(reference, Locale.ENGLISH))
|
||||||
|
|
||||||
|
val offset = OffsetDateTime.of(2021, 1, 6, 0, 0, 0, 0, ZoneOffset.UTC)
|
||||||
|
val actual = Localization.relativeTime(offset)
|
||||||
|
|
||||||
|
assertEquals("5 days from now", actual)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user