From aed4278388e9d9264ec3465a60d1ed1db9492ae7 Mon Sep 17 00:00:00 2001 From: Stypox Date: Fri, 5 Sep 2025 17:16:43 +0200 Subject: [PATCH] Unify getString for compatibility (read the method's javadoc for why) --- .../org/schabi/newpipe/error/ErrorInfo.kt | 9 ++-- .../MediaBrowserPlaybackPreparer.kt | 4 +- .../settings/viewmodel/SettingsViewModel.kt | 7 ++-- .../org/schabi/newpipe/util/Localization.java | 41 +++++++++++++++++++ .../schabi/newpipe/util/NavigationHelper.java | 7 ++-- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt index 609fbb336..a3c0aa993 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt @@ -28,6 +28,7 @@ import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentExcepti import org.schabi.newpipe.ktx.isNetworkRelated import org.schabi.newpipe.player.mediasource.FailedMediaSource import org.schabi.newpipe.player.resolver.PlaybackResolver +import org.schabi.newpipe.util.Localization import java.net.UnknownHostException /** @@ -147,13 +148,11 @@ class ErrorInfo private constructor( private vararg val formatArgs: String, ) : Parcelable { fun getString(context: Context): String { + // use Localization.compatGetString() just in case context is not AppCompatActivity return if (formatArgs.isEmpty()) { - // use ContextCompat.getString() just in case context is not AppCompatActivity - ContextCompat.getString(context, stringRes) + Localization.compatGetString(context, stringRes) } else { - // ContextCompat.getString() with formatArgs does not exist, so we just - // replicate its source code but with formatArgs - ContextCompat.getContextForLanguage(context).getString(stringRes, *formatArgs) + Localization.compatGetString(context, stringRes, *formatArgs) } } } diff --git a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt index 4815965a3..fbd506456 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt +++ b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt @@ -6,7 +6,6 @@ import android.os.Bundle import android.os.ResultReceiver import android.support.v4.media.session.PlaybackStateCompat import android.util.Log -import androidx.core.content.ContextCompat import androidx.core.net.toUri import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector.PlaybackPreparer @@ -29,6 +28,7 @@ import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue import org.schabi.newpipe.player.playqueue.SinglePlayQueue import org.schabi.newpipe.util.ChannelTabHelper import org.schabi.newpipe.util.ExtractorHelper +import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.NavigationHelper import java.util.function.BiConsumer import java.util.function.Consumer @@ -111,7 +111,7 @@ class MediaBrowserPlaybackPreparer( //region Errors private fun onUnsupportedError() { setMediaSessionError.accept( - ContextCompat.getString(context, R.string.content_not_supported), + Localization.compatGetString(context, R.string.content_not_supported), PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED ) } diff --git a/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt b/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt index ae3520c94..1e48fef5e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/viewmodel/SettingsViewModel.kt @@ -3,13 +3,13 @@ package org.schabi.newpipe.settings.viewmodel import android.app.Application import android.content.Context import android.content.SharedPreferences -import androidx.core.content.ContextCompat import androidx.lifecycle.AndroidViewModel import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import org.schabi.newpipe.R +import org.schabi.newpipe.util.Localization import javax.inject.Inject @HiltViewModel @@ -20,11 +20,12 @@ class SettingsViewModel @Inject constructor( private var _settingsLayoutRedesignPref: Boolean get() = preferenceManager.getBoolean( - ContextCompat.getString(getApplication(), R.string.settings_layout_redesign_key), false + Localization.compatGetString(getApplication(), R.string.settings_layout_redesign_key), + false ) set(value) { preferenceManager.edit().putBoolean( - ContextCompat.getString(getApplication(), R.string.settings_layout_redesign_key), + Localization.compatGetString(getApplication(), R.string.settings_layout_redesign_key), value ).apply() } diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java index 890981e90..f5bcc40d3 100644 --- a/app/src/main/java/org/schabi/newpipe/util/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java @@ -18,6 +18,7 @@ import androidx.annotation.Nullable; import androidx.annotation.PluralsRes; import androidx.annotation.StringRes; import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.content.ContextCompat; import androidx.core.math.MathUtils; import androidx.core.os.LocaleListCompat; import androidx.preference.PreferenceManager; @@ -71,6 +72,46 @@ public final class Localization { private Localization() { } + /** + * Gets a string like you would normally do with {@link Context#getString}, except that when + * Context is not an AppCompatActivity the correct locale is still used. The latter step uses + * {@link ContextCompat#getString}, which might fail if the Locale system service is not + * available (e.g. inside of Compose previews). In that case this method falls back to plain old + * {@link Context#getString}. + *

This method also supports format args (see {@link #compatGetString(Context, int, + * Object...)}, unlike {@link ContextCompat#getString}.

+ * + * @param context any Android context, even the App context + * @param resId the string resource to resolve + * @return the resolved string + */ + public static String compatGetString(final Context context, @StringRes final int resId) { + try { + return ContextCompat.getString(context, resId); + } catch (final Throwable e) { + return context.getString(resId); + } + } + + /** + * @see #compatGetString(Context, int) + * @param context any Android context, even the App context + * @param resId the string resource to resolve + * @param formatArgs the formatting arguments + * @return the resolved string + */ + public static String compatGetString(final Context context, + @StringRes final int resId, + final Object... formatArgs) { + try { + // ContextCompat.getString() with formatArgs does not exist, so we just + // replicate its source code but with formatArgs + return ContextCompat.getContextForLanguage(context).getString(resId, formatArgs); + } catch (final Throwable e) { + return context.getString(resId, formatArgs); + } + } + @NonNull public static String concatenateStrings(final String... strings) { return concatenateStrings(DOT_SEPARATOR, Arrays.asList(strings)); diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index cc260d254..0a7906b8d 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -641,10 +641,9 @@ public final class NavigationHelper { public static void openSettings(final Context context) { final Class settingsClass = PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean( - ContextCompat.getString(context, R.string.settings_layout_redesign_key), - false - ) ? SettingsV2Activity.class : SettingsActivity.class; + .getBoolean(Localization.compatGetString(context, + R.string.settings_layout_redesign_key), false) + ? SettingsV2Activity.class : SettingsActivity.class; final Intent intent = new Intent(context, settingsClass); context.startActivity(intent);