diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/DarkModeSetting.java b/app/src/main/java/it/niedermann/owncloud/notes/android/DarkModeSetting.java new file mode 100644 index 00000000..e9d6a0a0 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/DarkModeSetting.java @@ -0,0 +1,64 @@ +package it.niedermann.owncloud.notes.android; + +import androidx.appcompat.app.AppCompatDelegate; + +import java.util.NoSuchElementException; + +/** + * Possible values of the Dark Mode Setting. + *

+ * The Dark Mode Setting can be stored in {@link android.content.SharedPreferences} as String by using {@link DarkModeSetting#name()} and received via {@link DarkModeSetting#valueOf(String)}. + *

+ * Additionally, the equivalent {@link AppCompatDelegate}-Mode can be received via {@link #getModeId()}. To convert a {@link AppCompatDelegate}-Mode to a {@link DarkModeSetting}, use {@link #fromModeID(int)} + * + * @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), + /** + * Always use dark mode. + */ + DARK(AppCompatDelegate.MODE_NIGHT_YES), + /** + * Follow the global system setting for dark mode. + */ + SYSTEM_DEFAULT(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); + + private final int modeId; + + DarkModeSetting(int modeId) { + this.modeId = modeId; + } + + public int getModeId() { + return modeId; + } + + /** + * Returns the instance of {@link DarkModeSetting} that corresponds to the ModeID of {@link AppCompatDelegate} + *

+ * Possible ModeIDs are: + *

+ * + * @param id One of the {@link AppCompatDelegate}-Night-Modes + * @return An instance of {@link DarkModeSetting} + */ + public static DarkModeSetting fromModeID(int id) { + for (DarkModeSetting value : DarkModeSetting.values()) { + if (value.modeId == id) { + return value; + } + } + + throw new NoSuchElementException("No NightMode with ID " + id + " found"); + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java index 0d60bef7..d08a830e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java @@ -59,7 +59,7 @@ public class SelectSingleNoteActivity extends NotesListViewActivity { sp.putLong(SingleNoteWidget.WIDGET_KEY + appWidgetId, noteID); sp.putLong(SingleNoteWidget.ACCOUNT_ID_KEY + appWidgetId, note.getAccountId()); - sp.putBoolean(SingleNoteWidget.DARK_THEME_KEY + appWidgetId, Notes.getAppTheme(getApplicationContext())); + sp.putString(SingleNoteWidget.DARK_THEME_KEY + appWidgetId, Notes.getAppTheme(getApplicationContext()).name()); sp.apply(); Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java index a9a477cc..1922a625 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java @@ -13,8 +13,10 @@ import android.util.Log; import android.widget.RemoteViews; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.DarkModeSetting; import it.niedermann.owncloud.notes.android.activity.EditNoteActivity; import it.niedermann.owncloud.notes.android.activity.NotesListViewActivity; +import it.niedermann.owncloud.notes.util.Notes; public class NoteListWidget extends AppWidgetProvider { private static final String TAG = NoteListWidget.class.getSimpleName(); @@ -28,7 +30,7 @@ public class NoteListWidget extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds) { RemoteViews views; - boolean darkTheme; + String darkTheme; for (int appWidgetId : appWidgetIds) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); @@ -40,7 +42,7 @@ public class NoteListWidget extends AppWidgetProvider { } String category = sp.getString(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, null); - darkTheme = sp.getBoolean(NoteListWidget.DARK_THEME_KEY + appWidgetId, false); + darkTheme = sp.getString(NoteListWidget.DARK_THEME_KEY + appWidgetId, DarkModeSetting.SYSTEM_DEFAULT.name()); Intent serviceIntent = new Intent(context, NoteListWidgetService.class); serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); @@ -70,7 +72,7 @@ public class NoteListWidget extends AppWidgetProvider { (new Intent(context, EditNoteActivity.class)), PendingIntent.FLAG_UPDATE_CURRENT); - if (darkTheme) { + if (Notes.isDarkThemeActive(context, DarkModeSetting.valueOf(darkTheme))) { views = new RemoteViews(context.getPackageName(), R.layout.widget_note_list_dark); views.setTextViewText(R.id.widget_note_list_title_tv_dark, getWidgetTitle(context, displayMode, category)); views.setOnClickPendingIntent(R.id.widget_note_header_icon_dark, openAppI); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetConfiguration.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetConfiguration.java index e73636ee..640fe8ac 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetConfiguration.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetConfiguration.java @@ -100,7 +100,7 @@ public class NoteListWidgetConfiguration extends AppCompatActivity { } sp.putLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, localAccount.getId()); - sp.putBoolean(NoteListWidget.DARK_THEME_KEY + appWidgetId, Notes.getAppTheme(getApplicationContext())); + sp.putString(NoteListWidget.DARK_THEME_KEY + appWidgetId, Notes.getAppTheme(getApplicationContext()).name()); sp.apply(); Intent updateIntent = new Intent( AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java index 773efdcd..0e6822e6 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java @@ -13,9 +13,11 @@ import android.widget.RemoteViewsService; import java.util.List; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.DarkModeSetting; import it.niedermann.owncloud.notes.android.activity.EditNoteActivity; import it.niedermann.owncloud.notes.model.DBNote; import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; +import it.niedermann.owncloud.notes.util.Notes; public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFactory { private final Context context; @@ -32,7 +34,9 @@ public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFact AppWidgetManager.INVALID_APPWIDGET_ID); final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this.context); displayMode = sp.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1); - darkTheme = sp.getBoolean(NoteListWidget.DARK_THEME_KEY + appWidgetId, false); + String themeName = sp.getString(NoteListWidget.DARK_THEME_KEY + appWidgetId, DarkModeSetting.SYSTEM_DEFAULT.name()); + DarkModeSetting theme = DarkModeSetting.valueOf(themeName); + darkTheme = Notes.isDarkThemeActive(context, theme); category = sp.getString(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, ""); accountId = sp.getLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, -1); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java index 0b7020d5..c1e5679b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java @@ -12,8 +12,10 @@ import android.preference.PreferenceManager; import android.widget.RemoteViews; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.DarkModeSetting; import it.niedermann.owncloud.notes.android.activity.EditNoteActivity; import it.niedermann.owncloud.notes.android.fragment.BaseNoteFragment; +import it.niedermann.owncloud.notes.util.Notes; public class SingleNoteWidget extends AppWidgetProvider { @@ -32,7 +34,8 @@ public class SingleNoteWidget extends AppWidgetProvider { return; } - boolean darkTheme = sp.getBoolean(DARK_THEME_KEY + appWidgetId, false); + String darkThemeName = sp.getString(DARK_THEME_KEY + appWidgetId, DarkModeSetting.SYSTEM_DEFAULT.name()); + DarkModeSetting darkTheme = DarkModeSetting.valueOf(darkThemeName); templateIntent.putExtra(BaseNoteFragment.PARAM_ACCOUNT_ID, sp.getLong(ACCOUNT_ID_KEY + appWidgetId, -1)); PendingIntent templatePendingIntent = PendingIntent.getActivity(context, appWidgetId, templateIntent, @@ -44,7 +47,7 @@ public class SingleNoteWidget extends AppWidgetProvider { RemoteViews views; - if (darkTheme) { + if (Notes.isDarkThemeActive(context, darkTheme)) { views = new RemoteViews(context.getPackageName(), R.layout.widget_single_note_dark); views.setPendingIntentTemplate(R.id.single_note_widget_lv_dark, templatePendingIntent); views.setRemoteAdapter(R.id.single_note_widget_lv_dark, serviceIntent); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidgetFactory.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidgetFactory.java index 4746d026..557a83c9 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidgetFactory.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidgetFactory.java @@ -14,10 +14,12 @@ import com.yydcdut.markdown.MarkdownProcessor; import com.yydcdut.markdown.syntax.text.TextFactory; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.DarkModeSetting; import it.niedermann.owncloud.notes.android.activity.EditNoteActivity; import it.niedermann.owncloud.notes.model.DBNote; import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; import it.niedermann.owncloud.notes.util.MarkDownUtil; +import it.niedermann.owncloud.notes.util.Notes; public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFactory { @@ -28,7 +30,7 @@ public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFa private NoteSQLiteOpenHelper db; private DBNote note; private final SharedPreferences sp; - private static Boolean darkTheme; + private static boolean darkModeActive; private static final String TAG = SingleNoteWidget.class.getSimpleName(); @@ -37,10 +39,11 @@ public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFa appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); sp = PreferenceManager.getDefaultSharedPreferences(this.context); - darkTheme = sp.getBoolean(SingleNoteWidget.DARK_THEME_KEY + appWidgetId, false); + String themeName = sp.getString(SingleNoteWidget.DARK_THEME_KEY + appWidgetId, DarkModeSetting.SYSTEM_DEFAULT.name()); + darkModeActive = Notes.isDarkThemeActive(context, DarkModeSetting.valueOf(themeName)); markdownProcessor = new MarkdownProcessor(this.context); markdownProcessor.factory(TextFactory.create()); - markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(this.context, darkTheme).build()); + markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(this.context, darkModeActive).build()); } @Override @@ -101,7 +104,7 @@ public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFa extras.putLong(EditNoteActivity.PARAM_ACCOUNT_ID, note.getAccountId()); fillInIntent.putExtras(extras); fillInIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - if (darkTheme) { + if (darkModeActive) { note_content = new RemoteViews(context.getPackageName(), R.layout.widget_single_note_content_dark); note_content.setOnClickFillInIntent(R.id.single_note_content_tv_dark, fillInIntent); note_content.setTextViewText(R.id.single_note_content_tv_dark, markdownProcessor.parse(note.getContent())); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java index ac24265a..84b8820b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java @@ -10,6 +10,7 @@ import androidx.preference.PreferenceFragmentCompat; import androidx.preference.SwitchPreference; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.DarkModeSetting; import it.niedermann.owncloud.notes.persistence.SyncWorker; import it.niedermann.owncloud.notes.util.Notes; @@ -26,10 +27,10 @@ public class PreferencesFragment extends PreferenceFragmentCompat { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); - final SwitchPreference themePref = findPreference(getString(R.string.pref_key_theme)); + final ListPreference themePref = findPreference(getString(R.string.pref_key_theme)); assert themePref != null; themePref.setOnPreferenceChangeListener((preference, newValue) -> { - Notes.setAppTheme((Boolean) newValue); + Notes.setAppTheme(DarkModeSetting.valueOf((String) newValue)); getActivity().setResult(Activity.RESULT_OK); getActivity().recreate(); return true; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java index e9bf9285..46d665c0 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java @@ -36,7 +36,7 @@ public class MarkDownUtil { * @return RxMDConfiguration */ public static Builder getMarkDownConfiguration(Context context) { - return getMarkDownConfiguration(context, Notes.getAppTheme(context)); + return getMarkDownConfiguration(context, Notes.isDarkThemeActive(context)); } public static Builder getMarkDownConfiguration(Context context, Boolean darkTheme) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java b/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java index 75f43f05..79105661 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java @@ -3,9 +3,13 @@ package it.niedermann.owncloud.notes.util; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.preference.PreferenceManager; + import androidx.appcompat.app.AppCompatDelegate; +import it.niedermann.owncloud.notes.android.DarkModeSetting; + public class Notes extends Application { private static final String DARK_THEME = "darkTheme"; @@ -15,16 +19,26 @@ public class Notes extends Application { super.onCreate(); } - public static void setAppTheme(Boolean darkTheme) { - if (darkTheme) { - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + public static void setAppTheme(DarkModeSetting setting) { + AppCompatDelegate.setDefaultNightMode(setting.getModeId()); + } + + public static DarkModeSetting getAppTheme(Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + String mode = prefs.getString(DARK_THEME, DarkModeSetting.SYSTEM_DEFAULT.name()); + return DarkModeSetting.valueOf(mode); + } + + public static boolean isDarkThemeActive(Context context, DarkModeSetting setting) { + if (setting == DarkModeSetting.SYSTEM_DEFAULT) { + return isDarkThemeActive(context); } else { - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + return setting == DarkModeSetting.DARK; } } - public static boolean getAppTheme(Context context) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getBoolean(DARK_THEME, false); + public static boolean isDarkThemeActive(Context context) { + int uiMode = context.getResources().getConfiguration().uiMode; + return (uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index cc342086..3fd107e9 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -10,6 +10,11 @@ @string/pref_value_font_size_medium @string/pref_value_font_size_large + + @string/pref_value_theme_light + @string/pref_value_theme_dark + @string/pref_value_theme_system_default + @string/pref_value_sync_off @string/pref_value_sync_15_minutes diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec594e6c..93c53eab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,8 +125,10 @@ 15_minutes 1_hour 6_hours + LIGHT + DARK + SYSTEM_DEFAULT - Light Normal Sync on Wi-Fi and mobile data @@ -179,6 +181,12 @@ 6 hours + + Light + Dark + System Default + + %d selected diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 9f61df31..86ce545d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -11,8 +11,11 @@ android:summary="%s" android:title="@string/settings_note_mode" /> -