diff --git a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java index 8126bd2c56b..e2ac2c20d97 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java @@ -18,40 +18,43 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment { private static final boolean CAPTIONING_SETTINGS_ACCESSIBLE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - /** - * Theme that was applied when the settings was opened (or recreated after a theme change). - */ - private String startThemeKey; - private final Preference.OnPreferenceChangeListener themePreferenceChange - = new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(final Preference preference, final Object newValue) { - defaultPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, true).apply(); - defaultPreferences.edit() - .putString(getString(R.string.theme_key), newValue.toString()).apply(); - - if (!newValue.equals(startThemeKey) && getActivity() != null) { - // If it's not the current theme - ActivityCompat.recreate(requireActivity()); - } - - return false; - } - }; private String captionSettingsKey; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + final String themeKey = getString(R.string.theme_key); - startThemeKey = defaultPreferences + // the key of the active theme when settings were opened (or recreated after theme change) + final String startThemeKey = defaultPreferences .getString(themeKey, getString(R.string.default_theme_value)); - findPreference(themeKey).setOnPreferenceChangeListener(themePreferenceChange); + final String autoDeviceThemeKey = getString(R.string.auto_device_theme_key); + findPreference(themeKey).setOnPreferenceChangeListener((preference, newValue) -> { + if (newValue.toString().equals(autoDeviceThemeKey)) { + Toast.makeText(getContext(), getString(R.string.select_night_theme_toast), + Toast.LENGTH_LONG).show(); + } + + applyThemeChange(startThemeKey, themeKey, newValue); + return false; + }); + + final String nightThemeKey = getString(R.string.night_theme_key); + if (startThemeKey.equals(autoDeviceThemeKey)) { + final String startNightThemeKey = defaultPreferences + .getString(nightThemeKey, getString(R.string.default_night_theme_value)); + + findPreference(nightThemeKey).setOnPreferenceChangeListener((preference, newValue) -> { + applyThemeChange(startNightThemeKey, nightThemeKey, newValue); + return false; + }); + } else { + removePreference(nightThemeKey); + } captionSettingsKey = getString(R.string.caption_settings_key); if (!CAPTIONING_SETTINGS_ACCESSIBLE) { - final Preference captionSettings = findPreference(captionSettingsKey); - getPreferenceScreen().removePreference(captionSettings); + removePreference(captionSettingsKey); } } @@ -72,4 +75,23 @@ public boolean onPreferenceTreeClick(final Preference preference) { return super.onPreferenceTreeClick(preference); } + + private void removePreference(final String preferenceKey) { + final Preference preference = findPreference(preferenceKey); + if (preference != null) { + getPreferenceScreen().removePreference(preference); + } + } + + private void applyThemeChange(final String beginningThemeKey, + final String themeKey, + final Object newValue) { + defaultPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, true).apply(); + defaultPreferences.edit().putString(themeKey, newValue.toString()).apply(); + + if (!newValue.equals(beginningThemeKey) && getActivity() != null) { + // if it's not the current theme + ActivityCompat.recreate(getActivity()); + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java index 4de166a5599..c445928c4df 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java @@ -48,7 +48,7 @@ public static void initSettings(final Context context) { @Override protected void onCreate(final Bundle savedInstanceBundle) { - setTheme(ThemeHelper.getSettingsThemeStyle(this)); + ThemeHelper.setTheme(this); assureCorrectAppLanguage(this); super.onCreate(savedInstanceBundle); diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index 5ac4de84ce3..0c890dddc41 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -21,9 +21,10 @@ import android.app.Activity; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.content.res.TypedArray; import android.util.TypedValue; -import android.view.ContextThemeWrapper; import androidx.annotation.AttrRes; import androidx.annotation.Nullable; @@ -39,7 +40,8 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException; public final class ThemeHelper { - private ThemeHelper() { } + private ThemeHelper() { + } /** * Apply the selected theme (on NewPipe settings) in the context @@ -70,31 +72,12 @@ public static void setTheme(final Context context, final int serviceId) { * @return whether the light theme is selected */ public static boolean isLightThemeSelected(final Context context) { - return getSelectedThemeString(context).equals(context.getResources() - .getString(R.string.light_theme_key)); - } - - - /** - * Create and return a wrapped context with the default selected theme set. - * - * @param baseContext the base context for the wrapper - * @return a wrapped-styled context - */ - public static Context getThemedContext(final Context baseContext) { - return new ContextThemeWrapper(baseContext, getThemeForService(baseContext, -1)); - } + final String selectedThemeKey = getSelectedThemeKey(context); + final Resources res = context.getResources(); - /** - * Return the selected theme without being styled to any service. - * See {@link #getThemeForService(Context, int)}. - * - * @param context context to get the selected theme - * @return the selected style (the default one) - */ - @StyleRes - public static int getDefaultTheme(final Context context) { - return getThemeForService(context, -1); + return selectedThemeKey.equals(res.getString(R.string.light_theme_key)) + || (selectedThemeKey.equals(res.getString(R.string.auto_device_theme_key)) + && !isDeviceDarkThemeEnabled(context)); } /** @@ -130,71 +113,60 @@ public static int getMinWidthDialogTheme(final Context context) { */ @StyleRes public static int getThemeForService(final Context context, final int serviceId) { - final String lightTheme = context.getResources().getString(R.string.light_theme_key); - final String darkTheme = context.getResources().getString(R.string.dark_theme_key); - final String blackTheme = context.getResources().getString(R.string.black_theme_key); - - final String selectedTheme = getSelectedThemeString(context); - - int defaultTheme = R.style.DarkTheme; - if (selectedTheme.equals(lightTheme)) { - defaultTheme = R.style.LightTheme; - } else if (selectedTheme.equals(blackTheme)) { - defaultTheme = R.style.BlackTheme; - } else if (selectedTheme.equals(darkTheme)) { - defaultTheme = R.style.DarkTheme; + final Resources res = context.getResources(); + final String lightThemeKey = res.getString(R.string.light_theme_key); + final String blackThemeKey = res.getString(R.string.black_theme_key); + final String automaticDeviceThemeKey = res.getString(R.string.auto_device_theme_key); + + final String selectedThemeKey = getSelectedThemeKey(context); + + int baseTheme = R.style.DarkTheme; // default to dark theme + if (selectedThemeKey.equals(lightThemeKey)) { + baseTheme = R.style.LightTheme; + } else if (selectedThemeKey.equals(blackThemeKey)) { + baseTheme = R.style.BlackTheme; + } else if (selectedThemeKey.equals(automaticDeviceThemeKey)) { + + if (isDeviceDarkThemeEnabled(context)) { + // use the dark theme variant preferred by the user + final String selectedNightThemeKey = getSelectedNightThemeKey(context); + if (selectedNightThemeKey.equals(blackThemeKey)) { + baseTheme = R.style.BlackTheme; + } else { + baseTheme = R.style.DarkTheme; + } + } else { + // there is only one day theme + baseTheme = R.style.LightTheme; + } } if (serviceId <= -1) { - return defaultTheme; + return baseTheme; } final StreamingService service; try { service = NewPipe.getService(serviceId); } catch (final ExtractionException ignored) { - return defaultTheme; + return baseTheme; } - String themeName = "DarkTheme"; - if (selectedTheme.equals(lightTheme)) { + String themeName = "DarkTheme"; // default + if (baseTheme == R.style.LightTheme) { themeName = "LightTheme"; - } else if (selectedTheme.equals(blackTheme)) { + } else if (baseTheme == R.style.BlackTheme) { themeName = "BlackTheme"; - } else if (selectedTheme.equals(darkTheme)) { - themeName = "DarkTheme"; } themeName += "." + service.getServiceInfo().getName(); - final int resourceId = context - .getResources() + final int resourceId = context.getResources() .getIdentifier(themeName, "style", context.getPackageName()); if (resourceId > 0) { return resourceId; } - - return defaultTheme; - } - - @StyleRes - public static int getSettingsThemeStyle(final Context context) { - final String lightTheme = context.getResources().getString(R.string.light_theme_key); - final String darkTheme = context.getResources().getString(R.string.dark_theme_key); - final String blackTheme = context.getResources().getString(R.string.black_theme_key); - - final String selectedTheme = getSelectedThemeString(context); - - if (selectedTheme.equals(lightTheme)) { - return R.style.LightSettingsTheme; - } else if (selectedTheme.equals(blackTheme)) { - return R.style.BlackSettingsTheme; - } else if (selectedTheme.equals(darkTheme)) { - return R.style.DarkSettingsTheme; - } else { - // Fallback - return R.style.DarkSettingsTheme; - } + return baseTheme; } /** @@ -229,18 +201,27 @@ public static int resolveColorFromAttr(final Context context, @AttrRes final int return value.data; } - private static String getSelectedThemeString(final Context context) { + private static String getSelectedThemeKey(final Context context) { final String themeKey = context.getString(R.string.theme_key); final String defaultTheme = context.getResources().getString(R.string.default_theme_value); return PreferenceManager.getDefaultSharedPreferences(context) .getString(themeKey, defaultTheme); } + private static String getSelectedNightThemeKey(final Context context) { + final String nightThemeKey = context.getString(R.string.night_theme_key); + final String defaultNightTheme = context.getResources() + .getString(R.string.default_night_theme_value); + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(nightThemeKey, defaultNightTheme); + } + /** * Sets the title to the activity, if the activity is an {@link AppCompatActivity} and has an * action bar. + * * @param activity the activity to set the title of - * @param title the title to set to the activity + * @param title the title to set to the activity */ public static void setTitleToAppCompatActivity(@Nullable final Activity activity, final CharSequence title) { @@ -251,4 +232,27 @@ public static void setTitleToAppCompatActivity(@Nullable final Activity activity } } } + + /** + * Get the device theme + *

+ * It will return true if the device 's theme is dark, false otherwise. + *

+ * From https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#java + * + * @param context the context to use + * @return true:dark theme, false:light or unknown + */ + public static boolean isDeviceDarkThemeEnabled(final Context context) { + final int deviceTheme = context.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK; + switch (deviceTheme) { + case Configuration.UI_MODE_NIGHT_YES: + return true; + case Configuration.UI_MODE_NIGHT_UNDEFINED: + case Configuration.UI_MODE_NIGHT_NO: + default: + return false; + } + } } diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 38e83b6628d..2f2a9622c60 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -23,6 +23,7 @@ Etoso Malluma Luma + Nigra Elŝuti Ligilo ne subtenita Preferata enhavlingvo @@ -90,7 +91,6 @@ Montri pli altajn rezoluciojn Nur kelkaj aparatoj povas ludi 2K / 4K filmetojn Defaŭlta fomato de filmeto - Nigra Memoru ŝprucfenestran grandecon kaj pozicion Memoru lastan grandecon kaj pozicion de ŝprucfenestro Uzi rapide, ne precizan serĉon diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 86f4fe09c0a..6020f8cb18a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -41,8 +41,10 @@ Utiliser Tor (Expérimental) Forcer la redirection du trafic de téléchargement via Tor pour plus de confidentialité (les flux vidéos ne sont pas encore pris en charge). Thème + Thème nuit Sombre Clair + Noir Apparence Erreur réseau Dossier de téléchargement audio @@ -103,7 +105,6 @@ Veuillez définir ultérieurement un dossier de téléchargement dans les paramètres Impossible de charger l’image L’application a planté - Noir Tout Chaîne Défi reCAPTCHA @@ -669,4 +670,7 @@ Ce contenu n\'est disponible que pour les abonnés, il ne peut donc pas être diffusé en continu ni téléchargé par NewPipe. Cette vidéo n\'est disponible que pour les membres de YouTube Music Premium, elle ne peut donc pas être diffusée en continu ni téléchargée par NewPipe. Ce contenu est privé, il ne peut donc pas être diffusé en continu ni téléchargé par NewPipe. + Automatique (thème de l\'appareil) + Choisissez votre thème nuit favori — %s + Vous pouvez chosir votre thème nuit favori \ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 0958fce26a9..9044c65aa60 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -176,19 +176,32 @@ theme + night_theme light_theme dark_theme black_theme + auto_device_theme @string/dark_theme_key + @string/dark_theme_key @string/light_theme_key @string/dark_theme_key @string/black_theme_key + @string/auto_device_theme_key @string/light_theme_title @string/dark_theme_title @string/black_theme_title + @string/auto_device_theme_title + + + @string/dark_theme_key + @string/black_theme_key + + + @string/dark_theme_title + @string/black_theme_title diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9fb15e4638f..99702dab06d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,6 +79,7 @@ Default audio format Default video format Theme + Night Theme Light Dark Black @@ -709,4 +710,7 @@ This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe. Featured Radio + Automatic (device theme) + Select your favorite night theme — %s + You can select your favorite night theme below diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml index 7f30d20910a..e5afef80530 100644 --- a/app/src/main/res/xml/appearance_settings.xml +++ b/app/src/main/res/xml/appearance_settings.xml @@ -12,6 +12,15 @@ android:title="@string/theme_title" app:iconSpaceReserved="false" /> + +