Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.Menu;
import android.view.MenuItem;
Expand Down Expand Up @@ -670,11 +671,50 @@ private static void add(
final AppearanceTheme currentTheme
= PrefsUtility.appearance_theme();

final String[] themeNames = activity.getResources()
.getStringArray(R.array.pref_appearance_theme);
// When following the system theme, the single theme
// key is ignored - the active theme is the light or
// dark selection for the current mode. Offer only the
// themes for that mode and write to its key, so every
// choice changes the theme currently on screen instead
// of silently doing nothing.
final String[] themeNames;
final String[] themeValues;
final String themeKey;
final int titleRes;

if(PrefsUtility.appearance_theme_use_system()) {

final int uiMode = activity.getResources()
.getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;

if(uiMode == Configuration.UI_MODE_NIGHT_YES) {
themeNames = activity.getResources().getStringArray(
R.array.pref_appearance_theme_dark);
themeValues = activity.getResources().getStringArray(
R.array.pref_appearance_theme_dark_return);
themeKey = activity.getString(
R.string.pref_appearance_theme_dark_key);
titleRes = R.string.pref_appearance_theme_dark_title;
} else {
themeNames = activity.getResources().getStringArray(
R.array.pref_appearance_theme_light);
themeValues = activity.getResources().getStringArray(
R.array.pref_appearance_theme_light_return);
themeKey = activity.getString(
R.string.pref_appearance_theme_light_key);
titleRes = R.string.pref_appearance_theme_light_title;
}

final String[] themeValues = activity.getResources()
.getStringArray(R.array.pref_appearance_theme_return);
} else {
themeNames = activity.getResources().getStringArray(
R.array.pref_appearance_theme);
themeValues = activity.getResources().getStringArray(
R.array.pref_appearance_theme_return);
themeKey = activity.getString(
R.string.pref_appearance_theme_key);
titleRes = R.string.pref_appearance_theme_title;
}

int selectedPos = -1;
for(int i = 0; i < themeValues.length; i++) {
Expand All @@ -688,17 +728,14 @@ private static void add(

final MaterialAlertDialogBuilder dialog
= new MaterialAlertDialogBuilder(activity);
dialog.setTitle(R.string.pref_appearance_theme_title);
dialog.setTitle(titleRes);

dialog.setSingleChoiceItems(
themeNames,
selectedPos,
(dialog1, item1) -> {
prefs.edit()
.putString(
activity.getString(
R.string.pref_appearance_theme_key),
themeValues[item1])
.putString(themeKey, themeValues[item1])
.apply();
dialog1.dismiss();
});
Expand Down
38 changes: 34 additions & 4 deletions src/main/java/org/quantumbadger/redreader/common/PrefsUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ public static boolean isRefreshRequired(final Context context, final String key)
public static boolean isRestartRequired(final Context context, final String key) {
return context.getString(R.string.pref_appearance_twopane_key).equals(key)
|| context.getString(R.string.pref_appearance_theme_key).equals(key)
|| context.getString(R.string.pref_appearance_theme_use_system_key).equals(key)
|| context.getString(R.string.pref_appearance_theme_light_key).equals(key)
|| context.getString(R.string.pref_appearance_theme_dark_key).equals(key)
|| context.getString(R.string.pref_appearance_navbar_color_key).equals(key)
|| context.getString(R.string.pref_appearance_langforce_key).equals(key)
|| context.getString(R.string.pref_behaviour_bezel_toolbar_swipezone_key)
Expand Down Expand Up @@ -206,15 +209,42 @@ public static AppearanceTwopane appearance_twopane() {
}

public static boolean isNightMode() {

final AppearanceTheme theme = appearance_theme();

final AppearanceTheme theme = appearance_theme(mRes);
return theme == AppearanceTheme.NIGHT
|| theme == AppearanceTheme.NIGHT_LOWCONTRAST
|| theme == AppearanceTheme.ULTRABLACK;
}

public static boolean appearance_theme_use_system() {
return getBoolean(R.string.pref_appearance_theme_use_system_key, false);
}

public static AppearanceTheme appearance_theme_light() {
return AppearanceTheme.valueOf(StringUtils.asciiUppercase(getString(
R.string.pref_appearance_theme_light_key,
"red")));
}

public static AppearanceTheme appearance_theme_dark() {
return AppearanceTheme.valueOf(StringUtils.asciiUppercase(getString(
R.string.pref_appearance_theme_dark_key,
"night")));
}

public static AppearanceTheme appearance_theme() {
return appearance_theme(mRes);
}

public static AppearanceTheme appearance_theme(@Nullable final Resources resources) {
if(resources != null && appearance_theme_use_system()) {
final int uiMode = resources.getConfiguration().uiMode
& android.content.res.Configuration.UI_MODE_NIGHT_MASK;
if(uiMode == android.content.res.Configuration.UI_MODE_NIGHT_YES) {
return appearance_theme_dark();
} else {
return appearance_theme_light();
}
}
return AppearanceTheme.valueOf(StringUtils.asciiUppercase(getString(
R.string.pref_appearance_theme_key,
"red")));
Expand All @@ -232,7 +262,7 @@ public static AppearanceNavbarColour appearance_navbar_colour() {

public static void applyTheme(@NonNull final Activity activity) {

final AppearanceTheme theme = appearance_theme();
final AppearanceTheme theme = appearance_theme(activity.getResources());

switch(theme) {
case RED:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
Expand Down Expand Up @@ -64,6 +65,7 @@

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -119,6 +121,8 @@ public void onCreatePreferences(
R.string.pref_behaviour_fling_comment_left_key,
R.string.pref_behaviour_fling_comment_right_key,
R.string.pref_appearance_theme_key,
R.string.pref_appearance_theme_light_key,
R.string.pref_appearance_theme_dark_key,
R.string.pref_appearance_navbar_color_key,
R.string.pref_cache_maxage_listing_key,
R.string.pref_cache_maxage_thumb_key,
Expand Down Expand Up @@ -235,6 +239,50 @@ public void onCreatePreferences(
});
}

{
final CheckBoxPreference useSystemThemePref =
findPreference(getString(R.string.pref_appearance_theme_use_system_key));
final ListPreference themePref =
findPreference(getString(R.string.pref_appearance_theme_key));
final ListPreference themeLightPref =
findPreference(getString(R.string.pref_appearance_theme_light_key));
final ListPreference themeDarkPref =
findPreference(getString(R.string.pref_appearance_theme_dark_key));

if(useSystemThemePref != null && themePref != null
&& themeLightPref != null && themeDarkPref != null) {

final boolean useSystem = useSystemThemePref.isChecked();
themePref.setVisible(!useSystem);
themeLightPref.setVisible(useSystem);
themeDarkPref.setVisible(useSystem);

useSystemThemePref.setOnPreferenceChangeListener((preference, newValue) -> {
final boolean nowUseSystem = Boolean.TRUE.equals(newValue);
themePref.setVisible(!nowUseSystem);
themeLightPref.setVisible(nowUseSystem);
themeDarkPref.setVisible(nowUseSystem);

// Carry the currently-active theme across the toggle so it
// isn't replaced by a stale value the user never chose.
if(nowUseSystem) {
// Turning on: route the single theme into its natural
// light or dark slot (themes are inherently one or the
// other). The active theme then still shows if it matches
// the current system mode; otherwise the mode-appropriate
// theme is shown, which is the point of following system.
carryThemeToSystemSlot(themePref, themeLightPref, themeDarkPref);
} else {
// Turning off: adopt whichever of light/dark is currently
// active for the system mode, so the single theme matches
// what is already on screen.
carryActiveThemeToSingle(themePref, themeLightPref, themeDarkPref);
}
return true;
});
}
}

{
final CheckBoxPreference notifPref =
findPreference(getString(R.string.pref_behaviour_notifications_key));
Expand Down Expand Up @@ -580,6 +628,64 @@ public void onCreatePreferences(
}
}

// When Follow system theme is turned on, move the single theme selection
// into its natural light or dark slot so the active theme carries over.
private void carryThemeToSystemSlot(
final ListPreference themePref,
final ListPreference themeLightPref,
final ListPreference themeDarkPref) {

final String value = themePref.getValue();
if(value == null) {
return;
}

if(isDarkThemeValue(value)) {
themeDarkPref.setValue(value);
updateListPreferenceSummary(themeDarkPref);
} else {
themeLightPref.setValue(value);
updateListPreferenceSummary(themeLightPref);
}
}

// When Follow system theme is turned off, adopt whichever of the light/dark
// selections is currently active for the system's mode, so the single theme
// matches what is already displayed.
private void carryActiveThemeToSingle(
final ListPreference themePref,
final ListPreference themeLightPref,
final ListPreference themeDarkPref) {

final int uiMode = getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;

final String value = uiMode == Configuration.UI_MODE_NIGHT_YES
? themeDarkPref.getValue()
: themeLightPref.getValue();

if(value != null) {
themePref.setValue(value);
updateListPreferenceSummary(themePref);
}
}

private boolean isDarkThemeValue(final String value) {
return Arrays.asList(getResources().getStringArray(
R.array.pref_appearance_theme_dark_return)).contains(value);
}

// setValue() persists and re-applies the theme, but the row summary is set
// manually elsewhere (and only via the change listener, which programmatic
// setValue does not trigger), so refresh it here to keep the displayed
// selection in sync without a settings reload.
private void updateListPreferenceSummary(final ListPreference pref) {
final int index = pref.findIndexOfValue(pref.getValue());
if(index >= 0) {
pref.setSummary(pref.getEntries()[index]);
}
}

//Based on https://stackoverflow.com/a/55724743
@Override
public void setPreferenceScreen(final PreferenceScreen preferenceScreen) {
Expand Down
32 changes: 32 additions & 0 deletions src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,38 @@
<item>ultrablack</item>
</string-array>

<string-array name="pref_appearance_theme_light">
<item>@string/theme_name_red</item>
<item>@string/theme_name_green</item>
<item>@string/theme_name_blue</item>
<item>@string/theme_name_ltblue</item>
<item>@string/theme_name_orange</item>
<item>@string/theme_name_gray</item>
</string-array>

<!-- Constants. Do not change. -->
<string-array name="pref_appearance_theme_light_return">
<item>red</item>
<item>green</item>
<item>blue</item>
<item>ltblue</item>
<item>orange</item>
<item>gray</item>
</string-array>

<string-array name="pref_appearance_theme_dark">
<item>@string/theme_name_night</item>
<item>@string/theme_name_night_lowcontrast</item>
<item>@string/theme_name_ultrablack</item>
</string-array>

<!-- Constants. Do not change. -->
<string-array name="pref_appearance_theme_dark_return">
<item>night</item>
<item>night_lowcontrast</item>
<item>ultrablack</item>
</string-array>

<string-array name="pref_appearance_langforce">
<item>@string/lang_auto</item>
<item>@string/lang_en</item>
Expand Down
7 changes: 7 additions & 0 deletions src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
<string name="pref_appearance_theme_key" translatable="false">pref_appearance_theme</string>
<string name="pref_appearance_theme_title">Theme</string>

<string name="pref_appearance_theme_use_system_key" translatable="false">pref_appearance_theme_use_system</string>
<string name="pref_appearance_theme_use_system_title">Follow system theme</string>
<string name="pref_appearance_theme_light_key" translatable="false">pref_appearance_theme_light</string>
<string name="pref_appearance_theme_light_title">Light theme</string>
<string name="pref_appearance_theme_dark_key" translatable="false">pref_appearance_theme_dark</string>
<string name="pref_appearance_theme_dark_title">Dark theme</string>

<string name="pref_appearance_fontscale_posts_key" translatable="false">pref_appearance_fontscale_posts</string>
<string name="pref_appearance_fontscale_posts_title">Post titles</string>

Expand Down
16 changes: 16 additions & 0 deletions src/main/res/xml/prefs_appearance.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,28 @@

<PreferenceCategory android:title="@string/pref_appearance_theme_header">

<CheckBoxPreference android:title="@string/pref_appearance_theme_use_system_title"
android:key="@string/pref_appearance_theme_use_system_key"
android:defaultValue="false"/>

<ListPreference android:title="@string/pref_appearance_theme_title"
android:key="@string/pref_appearance_theme_key"
android:entries="@array/pref_appearance_theme"
android:entryValues="@array/pref_appearance_theme_return"
android:defaultValue="red"/>

<ListPreference android:title="@string/pref_appearance_theme_light_title"
android:key="@string/pref_appearance_theme_light_key"
android:entries="@array/pref_appearance_theme_light"
android:entryValues="@array/pref_appearance_theme_light_return"
android:defaultValue="red"/>

<ListPreference android:title="@string/pref_appearance_theme_dark_title"
android:key="@string/pref_appearance_theme_dark_key"
android:entries="@array/pref_appearance_theme_dark"
android:entryValues="@array/pref_appearance_theme_dark_return"
android:defaultValue="night"/>

<ListPreference android:title="@string/pref_appearance_navbar_color_title"
android:key="@string/pref_appearance_navbar_color_key"
android:entries="@array/pref_appearance_navbar_color_options"
Expand Down
Loading