From 5c8567ec2d56f2cf8a2391b2a16c85aba8274779 Mon Sep 17 00:00:00 2001 From: Yuri Volkov Date: Fri, 18 Sep 2020 07:32:25 +0300 Subject: [PATCH] #28 Show, which Theme is being configured. Allow to switch "Dark theme" during changes of settings. --- .../prefs/ApplicationPreferences.java | 30 ++++++-- .../todoagenda/prefs/ColorThemeType.java | 75 +++++++++++++++++++ .../prefs/ColorsPreferencesFragment.java | 33 +++++++- .../todoagenda/prefs/InstanceSettings.java | 60 +++++++-------- .../todoagenda/prefs/RootFragment.java | 14 ++++ .../todoagenda/prefs/ThemeColors.java | 37 +++++---- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/preferences_root.xml | 2 + 8 files changed, 196 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/org/andstatus/todoagenda/prefs/ColorThemeType.java diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/ApplicationPreferences.java b/app/src/main/java/org/andstatus/todoagenda/prefs/ApplicationPreferences.java index 30b86f5b..fc4045ac 100644 --- a/app/src/main/java/org/andstatus/todoagenda/prefs/ApplicationPreferences.java +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/ApplicationPreferences.java @@ -21,7 +21,6 @@ import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_DAY_HEADER_ALIGNMENT; import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_DAY_HEADER_DATE_FORMAT; import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_DAY_HEADER_DATE_FORMAT_DEFAULT; -import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_DIFFERENT_COLORS_FOR_DARK; import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_ENTRY_DATE_FORMAT; import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_ENTRY_DATE_FORMAT_DEFAULT; import static org.andstatus.todoagenda.prefs.InstanceSettings.PREF_EVENTS_ENDED; @@ -75,6 +74,8 @@ import static org.andstatus.todoagenda.util.StringUtil.isEmpty; public class ApplicationPreferences { + static final String PREF_DIFFERENT_COLORS_FOR_DARK = "differentColorsForDark"; + private static final String PREF_COLOR_THEME_TYPE = "colorThemeType"; private ApplicationPreferences() { // prohibit instantiation @@ -91,10 +92,18 @@ public static void fromInstanceSettings(Context context, Integer widgetId) { setEventsEnded(context, settings.getEventsEnded()); setFillAllDayEvents(context, settings.getFillAllDayEvents()); setHideBasedOnKeywords(context, settings.getHideBasedOnKeywords()); - setInt(context, PREF_WIDGET_HEADER_BACKGROUND_COLOR, settings.colors().getWidgetHeaderBackgroundColor()); - setInt(context, PREF_PAST_EVENTS_BACKGROUND_COLOR, settings.colors().getPastEventsBackgroundColor()); - setInt(context, PREF_TODAYS_EVENTS_BACKGROUND_COLOR, settings.colors().getTodaysEventsBackgroundColor()); - setInt(context, PREF_EVENTS_BACKGROUND_COLOR, settings.colors().getEventsBackgroundColor()); + + ThemeColors colors = settings.colors(); + setString(context, PREF_COLOR_THEME_TYPE, colors.colorThemeType.value); + setBoolean(context, PREF_DIFFERENT_COLORS_FOR_DARK, colors.colorThemeType != ColorThemeType.SINGLE); + setInt(context, PREF_WIDGET_HEADER_BACKGROUND_COLOR, colors.getWidgetHeaderBackgroundColor()); + setInt(context, PREF_PAST_EVENTS_BACKGROUND_COLOR, colors.getPastEventsBackgroundColor()); + setInt(context, PREF_TODAYS_EVENTS_BACKGROUND_COLOR, colors.getTodaysEventsBackgroundColor()); + setInt(context, PREF_EVENTS_BACKGROUND_COLOR, colors.getEventsBackgroundColor()); + for (Map.Entry entry: colors.shadings.entrySet()) { + setString(context, entry.getKey().preferenceName, entry.getValue().name()); + } + setShowDaysWithoutEvents(context, settings.getShowDaysWithoutEvents()); setShowDayHeaders(context, settings.getShowDayHeaders()); setDateFormat(context, PREF_DAY_HEADER_DATE_FORMAT, settings.getDayHeaderDateFormat()); @@ -119,9 +128,6 @@ public static void fromInstanceSettings(Context context, Integer widgetId) { setString(context, PREF_FILTER_MODE, settings.getFilterMode().value); setBoolean(context, PREF_INDICATE_ALERTS, settings.getIndicateAlerts()); setBoolean(context, PREF_INDICATE_RECURRING, settings.getIndicateRecurring()); - for (Map.Entry entry: settings.colors().shadings.entrySet()) { - setString(context, entry.getKey().preferenceName, entry.getValue().name()); - } setBoolean(context, PREF_COMPACT_LAYOUT, settings.isCompactLayout()); setString(context, PREF_WIDGET_HEADER_LAYOUT, settings.getWidgetHeaderLayout().value); setString(context, PREF_TEXT_SIZE_SCALE, settings.getTextSizeScale().preferenceValue); @@ -202,6 +208,14 @@ public static boolean areDifferentColorsForDark(Context context) { return getBoolean(context, PREF_DIFFERENT_COLORS_FOR_DARK, false); } + static ColorThemeType getEditingColorThemeType(Context context) { + return getColorThemeType(context).fromEditor(context, areDifferentColorsForDark(context)); + } + + public static ColorThemeType getColorThemeType(Context context) { + return ColorThemeType.fromValue(getString(context, PREF_COLOR_THEME_TYPE, "")); + } + public static int getWidgetHeaderBackgroundColor(Context context) { return getInt(context, PREF_WIDGET_HEADER_BACKGROUND_COLOR, PREF_WIDGET_HEADER_BACKGROUND_COLOR_DEFAULT); diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/ColorThemeType.java b/app/src/main/java/org/andstatus/todoagenda/prefs/ColorThemeType.java new file mode 100644 index 00000000..9d3b25c4 --- /dev/null +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/ColorThemeType.java @@ -0,0 +1,75 @@ +package org.andstatus.todoagenda.prefs; + +import android.app.Activity; +import android.content.Context; +import android.os.Build; + +import androidx.annotation.StringRes; + +import org.andstatus.todoagenda.R; + +import static org.andstatus.todoagenda.prefs.InstanceSettings.isDarkThemeOn; + +/** + * See https://github.com/andstatus/todoagenda/issues/48 + * @author yvolk@yurivolkov.com + */ +public enum ColorThemeType { + SINGLE("single", R.string.appearance_group_color_title), + DARK("dark", R.string.colors_dark), + LIGHT("light", R.string.colors_light), + NONE("none", R.string.no_title); + + private final static ColorThemeType defaultValue = SINGLE; + + public final String value; + @StringRes + public final int titleResId; + + ColorThemeType(String value, int titleResId) { + this.value = value; + this.titleResId = titleResId; + } + + public boolean isValid() { + return this != NONE; + } + + public static ColorThemeType fromValue(String value) { + for (ColorThemeType item : ColorThemeType.values()) { + if (item.value.equals(value)) { + return item; + } + } + return defaultValue; + } + + /** See https://developer.android.com/guide/topics/ui/look-and-feel/darktheme */ + public static boolean canHaveDifferentColorsForDark() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + } + + public ColorThemeType fromEditor(Context context, boolean differentColorsForDark) { + if (differentColorsForDark && canHaveDifferentColorsForDark()) { + if (this == ColorThemeType.DARK || this == ColorThemeType.SINGLE && isDarkThemeOn(context)) { + return ColorThemeType.DARK; + } else { + return ColorThemeType.LIGHT; + } + } else { + if (this == ColorThemeType.LIGHT || this == ColorThemeType.SINGLE) { + return ColorThemeType.SINGLE; + } else { + return ColorThemeType.NONE; + } + } + } + + public ColorThemeType setTitle(Activity activity) { + if (activity != null) { + activity.setTitle(titleResId); + } + return this; + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/ColorsPreferencesFragment.java b/app/src/main/java/org/andstatus/todoagenda/prefs/ColorsPreferencesFragment.java index 0c4b3186..31132c7d 100644 --- a/app/src/main/java/org/andstatus/todoagenda/prefs/ColorsPreferencesFragment.java +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/ColorsPreferencesFragment.java @@ -1,9 +1,11 @@ package org.andstatus.todoagenda.prefs; +import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; @@ -12,11 +14,13 @@ import com.rarepebble.colorpicker.ColorPreference; import com.rarepebble.colorpicker.ColorPreferenceDialog; +import org.andstatus.todoagenda.MainActivity; import org.andstatus.todoagenda.R; import org.andstatus.todoagenda.TextShading; import org.andstatus.todoagenda.widget.TimeSection; import static org.andstatus.todoagenda.WidgetConfigurationActivity.FRAGMENT_TAG; +import static org.andstatus.todoagenda.prefs.ApplicationPreferences.PREF_DIFFERENT_COLORS_FOR_DARK; /** AndroidX version created by yvolk@yurivolkov.com * based on this answer: https://stackoverflow.com/a/53290775/297710 @@ -27,27 +31,39 @@ public class ColorsPreferencesFragment extends PreferenceFragmentCompat @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setTitle(); addPreferencesFromResource(R.xml.preferences_colors); removeUnavailablePreferences(); } + private void setTitle() { + ApplicationPreferences.getEditingColorThemeType(getActivity()).setTitle(getActivity()); + } + @Override public void onResume() { super.onResume(); + setTitle(); removeUnavailablePreferences(); getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); showShadings(); } private void removeUnavailablePreferences() { - if (!InstanceSettings.canHaveDifferentColorsForDark()) { + Context context = getActivity(); + if (context == null) return; + + ColorThemeType colorThemeType = ApplicationPreferences.getColorThemeType(context); + if (!ColorThemeType.canHaveDifferentColorsForDark() || + colorThemeType == ColorThemeType.LIGHT || + colorThemeType == ColorThemeType.SINGLE && !InstanceSettings.isDarkThemeOn(context)) { PreferenceScreen screen = getPreferenceScreen(); - Preference preference = findPreference(InstanceSettings.PREF_DIFFERENT_COLORS_FOR_DARK); + Preference preference = findPreference(PREF_DIFFERENT_COLORS_FOR_DARK); if (screen != null && preference != null) { screen.removePreference(preference); } } - if (ApplicationPreferences.noPastEvents(getActivity())) { + if (ApplicationPreferences.noPastEvents(context)) { PreferenceScreen screen = getPreferenceScreen(); Preference preference = findPreference(TimeSection.PAST.preferenceCategoryKey); if (screen != null && preference != null) { @@ -70,6 +86,17 @@ public void onPause() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (PREF_DIFFERENT_COLORS_FOR_DARK.equals(key)){ + FragmentActivity activity = getActivity(); + if (activity != null) { + if (ApplicationPreferences.getEditingColorThemeType(activity) == ColorThemeType.NONE) { + activity.startActivity(MainActivity.intentToConfigure(activity, ApplicationPreferences.getWidgetId(activity))); + activity.finish(); + return; + }; + setTitle(); + } + } showShadings(); } diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/InstanceSettings.java b/app/src/main/java/org/andstatus/todoagenda/prefs/InstanceSettings.java index a3560f73..fec3731b 100644 --- a/app/src/main/java/org/andstatus/todoagenda/prefs/InstanceSettings.java +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/InstanceSettings.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.res.Configuration; -import android.os.Build; import android.util.Log; import androidx.annotation.NonNull; @@ -87,9 +86,7 @@ public class InstanceSettings { // ---------------------------------------------------------------------------------- // Colors - static final String PREF_DIFFERENT_COLORS_FOR_DARK = "differentColorsForDark"; private ThemeColors defaultColors; - private boolean differentColorsForDark = false; static final String PREF_DARK_THEME = "darkTheme"; private ThemeColors darkColors = ThemeColors.EMPTY; @@ -207,11 +204,12 @@ private InstanceSettings setFromJson(JSONObject json) { hideBasedOnKeywords = json.getString(PREF_HIDE_BASED_ON_KEYWORDS); } - defaultColors = ThemeColors.fromJson(context, json); - differentColorsForDark = canHaveDifferentColorsForDark() && json.has(PREF_DARK_THEME); - if (differentColorsForDark) { - darkColors = ThemeColors.fromJson(context, json.getJSONObject(PREF_DARK_THEME)); - } + boolean differentColorsForDark = ColorThemeType.canHaveDifferentColorsForDark() && json.has(PREF_DARK_THEME); + defaultColors = ThemeColors.fromJson(context, + differentColorsForDark ? ColorThemeType.LIGHT : ColorThemeType.SINGLE, json); + darkColors = differentColorsForDark + ? ThemeColors.fromJson(context, ColorThemeType.DARK, json.getJSONObject(PREF_DARK_THEME)) + : ThemeColors.EMPTY; if (json.has(PREF_SHOW_DAYS_WITHOUT_EVENTS)) { showDaysWithoutEvents = json.getBoolean(PREF_SHOW_DAYS_WITHOUT_EVENTS); @@ -334,18 +332,25 @@ private InstanceSettings setFromApplicationPreferences(InstanceSettings settings fillAllDayEvents = ApplicationPreferences.getFillAllDayEvents(context); hideBasedOnKeywords = ApplicationPreferences.getHideBasedOnKeywords(context); - differentColorsForDark = canHaveDifferentColorsForDark() && ApplicationPreferences.areDifferentColorsForDark(context); - if (differentColorsForDark) { - if (isDarkThemeCurrent()) { - defaultColors = settingsStored.defaultColors; - darkColors = new ThemeColors(context).setFromApplicationPreferences(); - } else { - defaultColors = new ThemeColors(context).setFromApplicationPreferences(); - darkColors = settingsStored.darkColors; - } - } else { - defaultColors = new ThemeColors(context).setFromApplicationPreferences(); - darkColors = ThemeColors.EMPTY; + switch (ApplicationPreferences.getEditingColorThemeType(context)) { + case DARK: + darkColors = new ThemeColors(context, ColorThemeType.DARK).setFromApplicationPreferences(); + defaultColors = settingsStored.defaultColors.copy(context, ColorThemeType.LIGHT); + break; + case LIGHT: + darkColors = settingsStored.darkColors.isEmpty() + ? settingsStored.defaultColors.copy(context, ColorThemeType.DARK) + : settingsStored.darkColors.copy(context, ColorThemeType.DARK); + defaultColors = new ThemeColors(context, ColorThemeType.LIGHT).setFromApplicationPreferences(); + break; + case SINGLE: + darkColors = ThemeColors.EMPTY; + defaultColors = new ThemeColors(context, ColorThemeType.SINGLE).setFromApplicationPreferences(); + break; + case NONE: + darkColors = ThemeColors.EMPTY; + defaultColors = settingsStored.defaultColors.copy(context, ColorThemeType.SINGLE); + break; } showDaysWithoutEvents = ApplicationPreferences.getShowDaysWithoutEvents(context); @@ -396,7 +401,7 @@ public InstanceSettings(Context context, int widgetId, String proposedInstanceNa this.context = context; this.widgetId = widgetId; widgetInstanceName = AllSettings.uniqueInstanceName(context, widgetId, proposedInstanceName); - defaultColors = new ThemeColors(context); + defaultColors = context == null ? ThemeColors.EMPTY : new ThemeColors(context, ColorThemeType.SINGLE); } public boolean isEmpty() { @@ -433,7 +438,7 @@ public JSONObject toJson() { json.put(PREF_HIDE_BASED_ON_KEYWORDS, hideBasedOnKeywords); defaultColors.toJson(json); - if (differentColorsForDark) { + if (!darkColors.isEmpty()) { json.put(PREF_DARK_THEME, darkColors.toJson(new JSONObject())); } @@ -532,19 +537,12 @@ public String getHideBasedOnKeywords() { } public ThemeColors colors() { - return isDarkThemeCurrent() && darkColors != ThemeColors.EMPTY + return !darkColors.isEmpty() && isDarkThemeOn(context) ? darkColors : defaultColors; } - /** See https://developer.android.com/guide/topics/ui/look-and-feel/darktheme */ - public static boolean canHaveDifferentColorsForDark() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; - } - - private boolean isDarkThemeCurrent() { - if (!differentColorsForDark) return false; - + public static boolean isDarkThemeOn(Context context) { Configuration configuration = context.getApplicationContext().getResources().getConfiguration(); int currentNightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; return currentNightMode == Configuration.UI_MODE_NIGHT_YES; diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/RootFragment.java b/app/src/main/java/org/andstatus/todoagenda/prefs/RootFragment.java index 9c0ea8a1..4b1caf40 100644 --- a/app/src/main/java/org/andstatus/todoagenda/prefs/RootFragment.java +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/RootFragment.java @@ -1,7 +1,9 @@ package org.andstatus.todoagenda.prefs; +import android.content.Context; import android.os.Bundle; +import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import org.andstatus.todoagenda.R; @@ -15,10 +17,22 @@ public void onResume() { super.onResume(); Optional.ofNullable(getActivity()) .ifPresent(a -> a.setTitle(ApplicationPreferences.getWidgetInstanceName(a))); + setTitles(); } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences_root); + setTitles(); + } + + private void setTitles() { + Context context = getContext(); + Preference preference = findPreference("ColorsPreferencesFragment"); + if (context != null && preference != null) { + ColorThemeType themeType = ApplicationPreferences.getEditingColorThemeType(context); + preference.setTitle(themeType.titleResId); + preference.setVisible(themeType.isValid()); + } } } \ No newline at end of file diff --git a/app/src/main/java/org/andstatus/todoagenda/prefs/ThemeColors.java b/app/src/main/java/org/andstatus/todoagenda/prefs/ThemeColors.java index b6d06421..ab657ec2 100644 --- a/app/src/main/java/org/andstatus/todoagenda/prefs/ThemeColors.java +++ b/app/src/main/java/org/andstatus/todoagenda/prefs/ThemeColors.java @@ -2,7 +2,6 @@ import android.content.Context; import android.graphics.Color; -import android.os.Build; import android.util.Log; import android.view.ContextThemeWrapper; @@ -22,10 +21,9 @@ */ public class ThemeColors { private static final String TAG = ThemeColors.class.getSimpleName(); - final static ThemeColors EMPTY = new ThemeColors(null); + final static ThemeColors EMPTY = new ThemeColors(null, ColorThemeType.SINGLE); private final Context context; - - final Map shadings = new ConcurrentHashMap<>(); + public final ColorThemeType colorThemeType; static final String PREF_WIDGET_HEADER_BACKGROUND_COLOR = "widgetHeaderBackgroundColor"; @ColorInt @@ -41,8 +39,22 @@ public class ThemeColors { @ColorInt static final int PREF_EVENTS_BACKGROUND_COLOR_DEFAULT = 0x80000000; private int eventsBackgroundColor = PREF_EVENTS_BACKGROUND_COLOR_DEFAULT; - public static ThemeColors fromJson(Context context, JSONObject json) { - return new ThemeColors(context).setFromJson(json); + final Map shadings = new ConcurrentHashMap<>(); + + public static ThemeColors fromJson(Context context, ColorThemeType colorThemeType, JSONObject json) { + return new ThemeColors(context, colorThemeType).setFromJson(json); + } + + public ThemeColors(Context context, ColorThemeType colorThemeType) { + this.context = context; + this.colorThemeType = colorThemeType; + } + + public ThemeColors copy(Context context, ColorThemeType colorThemeType) { + ThemeColors themeColors = new ThemeColors(context, colorThemeType); + return isEmpty() + ? themeColors + : themeColors.setFromJson(toJson(new JSONObject())); } private ThemeColors setFromJson(JSONObject json) { @@ -86,10 +98,6 @@ ThemeColors setFromApplicationPreferences() { return this; } - public ThemeColors(Context context) { - this.context = context; - } - public JSONObject toJson(JSONObject json) { try { json.put(PREF_WIDGET_HEADER_BACKGROUND_COLOR, widgetHeaderBackgroundColor); @@ -109,11 +117,6 @@ public Context getContext() { return context; } - /** See https://developer.android.com/guide/topics/ui/look-and-feel/darktheme */ - public static boolean canHaveDifferentColorsForDark() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; - } - public int getWidgetHeaderBackgroundColor() { return widgetHeaderBackgroundColor; } @@ -130,6 +133,10 @@ public int getEventsBackgroundColor() { return eventsBackgroundColor; } + public boolean isEmpty() { + return context == null; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c614f0e3..f2744d98 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -127,6 +127,8 @@ for Dark/Light theme correspondingly. Colors and opacity of texts and backgrounds Colors + Colors for Light theme + Colors for Dark theme Background color Adjust the color of the background Past events background color diff --git a/app/src/main/res/xml/preferences_root.xml b/app/src/main/res/xml/preferences_root.xml index 5f7b1767..7debd69f 100644 --- a/app/src/main/res/xml/preferences_root.xml +++ b/app/src/main/res/xml/preferences_root.xml @@ -4,6 +4,8 @@ android:summary="@string/layout_prefs_desc" android:title="@string/layout_prefs_title" />