diff options
7 files changed, 130 insertions, 17 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java b/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java index cf30a0971..ba4088aa9 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java @@ -2,13 +2,14 @@ package it.niedermann.nextcloud.deck; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import androidx.annotation.NonNull; import androidx.multidex.MultiDexApplication; import androidx.preference.PreferenceManager; -import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO; -import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES; +import it.niedermann.nextcloud.deck.ui.settings.DarkModeSetting; + import static androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode; public class DeckApplication extends MultiDexApplication { @@ -17,9 +18,12 @@ public class DeckApplication extends MultiDexApplication { public static final long NO_BOARD_ID = -1L; public static final long NO_STACK_ID = -1L; + private static String PREF_KEY_THEME; + @Override public void onCreate() { - setAppTheme(isDarkTheme(getApplicationContext())); + PREF_KEY_THEME = getString(R.string.pref_key_dark_theme); + setAppTheme(getAppTheme(getApplicationContext())); super.onCreate(); } @@ -27,13 +31,37 @@ public class DeckApplication extends MultiDexApplication { // Day / Night theme // ----------------- - public static void setAppTheme(boolean darkTheme) { - setDefaultNightMode(darkTheme ? MODE_NIGHT_YES : MODE_NIGHT_NO); + public static void setAppTheme(DarkModeSetting setting) { + setDefaultNightMode(setting.getModeId()); } - public static boolean isDarkTheme(@NonNull Context context) { + public static DarkModeSetting getAppTheme(@NonNull Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getBoolean(context.getString(R.string.pref_key_dark_theme), false); + String mode; + try { + mode = prefs.getString(PREF_KEY_THEME, DarkModeSetting.SYSTEM_DEFAULT.getPreferenceValue(context)); + } catch (ClassCastException e) { + boolean darkModeEnabled = prefs.getBoolean(PREF_KEY_THEME, false); + mode = darkModeEnabled ? DarkModeSetting.DARK.getPreferenceValue(context) : DarkModeSetting.LIGHT.getPreferenceValue(context); + } + return DarkModeSetting.valueOf(mode); + } + + public static boolean isDarkThemeActive(@NonNull Context context, DarkModeSetting setting) { + if (setting == DarkModeSetting.SYSTEM_DEFAULT) { + return isDarkThemeActive(context); + } else { + return setting == DarkModeSetting.DARK; + } + } + + public static boolean isDarkThemeActive(@NonNull Context context) { + int uiMode = context.getResources().getConfiguration().uiMode; + return (uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + } + + public static boolean isDarkTheme(@NonNull Context context) { + return isDarkThemeActive(context, getAppTheme(context)); } // -------------------------------------- diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java index a491946ed..f06b25230 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java @@ -17,6 +17,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase; import it.niedermann.android.util.ColorUtil; import it.niedermann.nextcloud.deck.DeckLog; +import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.api.LastSyncUtil; import it.niedermann.nextcloud.deck.model.AccessControl; import it.niedermann.nextcloud.deck.model.Account; @@ -68,6 +69,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.projects.Oc import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.projects.OcsProjectResourceDao; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.widgets.SingleCardWidgetModelDao; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.widgets.StackWidgetModelDao; +import it.niedermann.nextcloud.deck.ui.settings.DarkModeSetting; @Database( entities = { @@ -97,7 +99,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.widgets.Sta UserInBoard.class, }, exportSchema = false, - version = 23 + version = 24 ) @TypeConverters({DateTypeConverter.class}) public abstract class DeckDatabase extends RoomDatabase { @@ -454,6 +456,22 @@ public abstract class DeckDatabase extends RoomDatabase { } }) .addMigrations(MIGRATION_22_23) + .addMigrations(new Migration(23, 24) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // https://github.com/stefan-niedermann/nextcloud-deck/issues/392 + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + final String themePref = context.getString(R.string.pref_key_dark_theme); + + if (sharedPreferences.contains(themePref)) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + final boolean darkTheme = sharedPreferences.getBoolean(themePref, false); + editor.remove(themePref); + editor.putString(themePref, darkTheme ? DarkModeSetting.DARK.getPreferenceValue(context) : DarkModeSetting.LIGHT.getPreferenceValue(context)); + editor.apply(); + } + } + }) .fallbackToDestructiveMigration() .addCallback(ON_CREATE_CALLBACK) .build(); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/DarkModeSetting.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/DarkModeSetting.java new file mode 100644 index 000000000..41e894666 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/DarkModeSetting.java @@ -0,0 +1,52 @@ +package it.niedermann.nextcloud.deck.ui.settings; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AppCompatDelegate; + +import it.niedermann.nextcloud.deck.R; + +/** + * Possible values of the Dark Mode Setting. + * <p> + * The Dark Mode Setting can be stored in {@link android.content.SharedPreferences} as String by using {@link DarkModeSetting#getPreferenceValue(Context)} and received via {@link DarkModeSetting#valueOf(String)}. + * <p> + * Additionally, the equivalent {@link AppCompatDelegate}-Mode can be received via {@link #getModeId()}. + * + * @see AppCompatDelegate#MODE_NIGHT_YES + * @see AppCompatDelegate#MODE_NIGHT_NO + * @see AppCompatDelegate#MODE_NIGHT_FOLLOW_SYSTEM + */ +public enum DarkModeSetting { + + /** + * Always use light mode. + */ + LIGHT(AppCompatDelegate.MODE_NIGHT_NO, R.string.pref_value_theme_light), + /** + * Always use dark mode. + */ + DARK(AppCompatDelegate.MODE_NIGHT_YES, R.string.pref_value_theme_dark), + /** + * Follow the global system setting for dark mode. + */ + SYSTEM_DEFAULT(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, R.string.pref_value_theme_system_default); + + private final int modeId; + private final @StringRes int preferenceValue; + + DarkModeSetting(int modeId, @StringRes int preferenceValue) { + this.modeId = modeId; + this.preferenceValue = preferenceValue; + } + + public int getModeId() { + return modeId; + } + + public String getPreferenceValue(@NonNull Context context) { + return context.getString(preferenceValue); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java index 04429f225..5a1d82389 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java @@ -21,7 +21,6 @@ import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMai public class SettingsFragment extends PreferenceFragmentCompat implements Branded { private BrandedSwitchPreference wifiOnlyPref; - private BrandedSwitchPreference themePref; private BrandedSwitchPreference brandingPref; private BrandedSwitchPreference compactPref; @@ -41,11 +40,11 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Brande DeckLog.error("Could not find preference with key: \"" + getString(R.string.pref_key_wifi_only) + "\""); } - themePref = findPreference(getString(R.string.pref_key_dark_theme)); + Preference themePref = findPreference(getString(R.string.pref_key_dark_theme)); if (themePref != null) { themePref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> { - final Boolean darkTheme = (Boolean) newValue; - DeckLog.log("darkTheme: " + darkTheme); + final DarkModeSetting darkTheme = DarkModeSetting.valueOf((String) newValue); + DeckLog.log("appTheme: " + darkTheme); setAppTheme(darkTheme); requireActivity().setResult(Activity.RESULT_OK); requireActivity().recreate(); @@ -93,7 +92,6 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Brande @Override public void applyBrand(int mainColor) { wifiOnlyPref.applyBrand(mainColor); - themePref.applyBrand(mainColor); brandingPref.applyBrand(mainColor); compactPref.applyBrand(mainColor); } diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml index c790a5868..ac4e7d73d 100644 --- a/app/src/main/res/values/setup.xml +++ b/app/src/main/res/values/setup.xml @@ -30,6 +30,16 @@ <item>@string/pref_value_background_6_hours</item> </string-array> + <string name="pref_value_theme_light" translatable="false">LIGHT</string> + <string name="pref_value_theme_dark" translatable="false">DARK</string> + <string name="pref_value_theme_system_default" translatable="false">SYSTEM_DEFAULT</string> + + <string-array name="darkMode_values"> + <item>@string/pref_value_theme_light</item> + <item>@string/pref_value_theme_dark</item> + <item>@string/pref_value_theme_system_default</item> + </string-array> + <!-- To be concatenated with the account id --> <string name="shared_preference_last_account" translatable="false">it.niedermann.nextcloud.deck.last_account</string> <string name="shared_preference_last_board_for_account_" translatable="false">it.niedermann.nextcloud.deck.last_board_for_account_</string> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8c29e67cd..2b347e3f1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -148,13 +148,17 @@ <string name="your_deck_version_is_too_old">Your deck version is too old</string> <string name="deck_outdated_please_update">Your deck version is too old (%1$s). Please update to use this android app as client.</string> <string name="delete_board_message">This will permanently delete this board including all lists and cards.</string> - <string name="settings_theme_title">Dark theme</string> + <string name="settings_theme_title">Theme</string> <string name="settings_branding_title">Branding</string> <string name="settings_compact_title">Compact mode</string> <string name="settings_background_sync">Background synchronization</string> <string name="pref_value_wifi_and_mobile">Sync on Wi-Fi and mobile data</string> <string name="pref_value_wifi_only">Sync only on Wi-Fi</string> - <string name="pref_value_theme_light">Light</string> + <string-array name="darkmode_entries"> + <item>Light</item> + <item>Dark</item> + <item>System Default</item> + </string-array> <string name="unassigned_user">Unassigned %1$s</string> <string name="no_activities">There are no activities on this card. You need to be connected to the internet to load and display activities.</string> <string name="share_board">Share board</string> diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 6d67622bd..1471e98ce 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -19,10 +19,13 @@ </it.niedermann.nextcloud.deck.ui.branding.BrandedPreferenceCategory> <it.niedermann.nextcloud.deck.ui.branding.BrandedPreferenceCategory android:title="@string/simple_appearance"> - <it.niedermann.nextcloud.deck.ui.branding.BrandedSwitchPreference - android:defaultValue="@string/pref_value_theme_light" + <ListPreference + android:defaultValue="@string/pref_value_theme_system_default" + android:entries="@array/darkmode_entries" + android:entryValues="@array/darkMode_values" android:icon="@drawable/ic_brightness_2_grey600_24dp" android:key="@string/pref_key_dark_theme" + android:summary="%s" android:title="@string/settings_theme_title" /> <it.niedermann.nextcloud.deck.ui.branding.BrandedSwitchPreference |