mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Added Support for System Wide Dark Theme (#3460)
* Added Support for System Wide Dark Theme * changed methods to private * Moved Strings to strings.xml * Used Dagger to reduce code repetition * Changes made as per review suggestions * Minor Changes * Fixes as per suggestions * Minor Fixes as per suggestion * made the variables static * removed irrelevant code
This commit is contained in:
parent
65ec071493
commit
1584ffe0e2
9 changed files with 139 additions and 42 deletions
|
|
@ -55,6 +55,7 @@ import fr.free.nrw.commons.explore.categories.ExploreActivity;
|
|||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import retrofit2.Call;
|
||||
|
|
@ -83,6 +84,9 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
@Inject
|
||||
LoginClient loginClient;
|
||||
|
||||
@Inject
|
||||
SystemThemeUtils systemThemeUtils;
|
||||
|
||||
@BindView(R.id.login_button)
|
||||
Button loginButton;
|
||||
|
||||
|
|
@ -121,7 +125,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
|
||||
boolean isDarkTheme = applicationKvStore.getBoolean("theme", false);
|
||||
boolean isDarkTheme = systemThemeUtils.isDeviceInNightMode();
|
||||
setTheme(isDarkTheme ? R.style.DarkAppTheme : R.style.LightAppTheme);
|
||||
getDelegate().installViewFactory();
|
||||
getDelegate().onCreate(savedInstanceState);
|
||||
|
|
@ -133,7 +137,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
usernameEdit.addTextChangedListener(textWatcher);
|
||||
passwordEdit.addTextChangedListener(textWatcher);
|
||||
twoFactorEdit.addTextChangedListener(textWatcher);
|
||||
|
||||
|
||||
if (ConfigUtils.isBetaFlavour()) {
|
||||
loginCredentials.setText(getString(R.string.login_credential));
|
||||
} else {
|
||||
|
|
@ -264,7 +268,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
new Callback<MwQueryResponse>() {
|
||||
@Override
|
||||
public void onResponse(Call<MwQueryResponse> call,
|
||||
Response<MwQueryResponse> response) {
|
||||
Response<MwQueryResponse> response) {
|
||||
loginClient.login(commonsWikiSite, username, password, null, twoFactorCode,
|
||||
response.body().query().loginToken(), new LoginCallback() {
|
||||
@Override
|
||||
|
|
@ -275,7 +279,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
|
||||
@Override
|
||||
public void twoFactorPrompt(@NonNull Throwable caught,
|
||||
@Nullable String token) {
|
||||
@Nullable String token) {
|
||||
Timber.d("Requesting 2FA prompt");
|
||||
hideProgress();
|
||||
askUserForTwoFactorAuth();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import android.content.IntentFilter;
|
|||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -93,6 +92,7 @@ import fr.free.nrw.commons.utils.LocationUtils;
|
|||
import fr.free.nrw.commons.utils.NearbyFABUtils;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||
import fr.free.nrw.commons.utils.UiUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||
|
|
@ -156,6 +156,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
@Inject ContributionController controller;
|
||||
@Inject WikidataEditListener wikidataEditListener;
|
||||
|
||||
@Inject
|
||||
SystemThemeUtils systemThemeUtils;
|
||||
|
||||
private NearbyFilterSearchRecyclerViewAdapter nearbyFilterSearchRecyclerViewAdapter;
|
||||
|
||||
private BottomSheetBehavior bottomSheetListBehavior;
|
||||
|
|
@ -210,7 +213,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
isDarkTheme = applicationKvStore.getBoolean("theme", false);
|
||||
isDarkTheme = systemThemeUtils.isDeviceInNightMode();
|
||||
cameraMoveListener= () -> presenter.onCameraMove(mapBox.getCameraPosition().target);
|
||||
addCheckBoxCallback();
|
||||
presenter.attachView(this);
|
||||
|
|
@ -821,10 +824,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}
|
||||
|
||||
private void showFABs() {
|
||||
NearbyFABUtils.addAnchorToBigFABs(fabPlus, bottomSheetDetails.getId());
|
||||
fabPlus.show();
|
||||
NearbyFABUtils.addAnchorToSmallFABs(fabGallery, getView().findViewById(R.id.empty_view).getId());
|
||||
NearbyFABUtils.addAnchorToSmallFABs(fabCamera, getView().findViewById(R.id.empty_view1).getId());
|
||||
NearbyFABUtils.addAnchorToBigFABs(fabPlus, bottomSheetDetails.getId());
|
||||
fabPlus.show();
|
||||
NearbyFABUtils.addAnchorToSmallFABs(fabGallery, getView().findViewById(R.id.empty_view).getId());
|
||||
NearbyFABUtils.addAnchorToSmallFABs(fabCamera, getView().findViewById(R.id.empty_view1).getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public class Prefs {
|
|||
public static final String IS_CONTRIBUTION_COUNT_CHANGED = "ccontributionCountChanged";
|
||||
public static final String MANAGED_EXIF_TAGS = "managed_exif_tags";
|
||||
public static final String KEY_LANGUAGE_VALUE = "languageDescription";
|
||||
public static final String KEY_THEME_VALUE = "appThemePref";
|
||||
|
||||
public static class Licenses {
|
||||
public static final String CC_BY_SA_3 = "CC BY-SA 3.0";
|
||||
|
|
|
|||
|
|
@ -12,18 +12,15 @@ import android.preference.SwitchPreference;
|
|||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.karumi.dexter.Dexter;
|
||||
import com.karumi.dexter.listener.PermissionGrantedResponse;
|
||||
import com.karumi.dexter.listener.single.BasePermissionListener;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
|
@ -37,14 +34,19 @@ import fr.free.nrw.commons.upload.Language;
|
|||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
|
||||
import static fr.free.nrw.commons.utils.SystemThemeUtils.THEME_MODE_DEFAULT;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragment {
|
||||
|
||||
@Inject
|
||||
@Named("default_preferences")
|
||||
JsonKvStore defaultKvStore;
|
||||
|
||||
@Inject
|
||||
CommonsLogSender commonsLogSender;
|
||||
private ListPreference listPreference;
|
||||
|
||||
private ListPreference themeListPreference;
|
||||
private ListPreference langListPreference;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -57,11 +59,8 @@ public class SettingsFragment extends PreferenceFragment {
|
|||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
SwitchPreference themePreference = (SwitchPreference) findPreference("theme");
|
||||
themePreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
getActivity().recreate();
|
||||
return true;
|
||||
});
|
||||
themeListPreference = (ListPreference) findPreference(Prefs.KEY_THEME_VALUE);
|
||||
prepareTheme();
|
||||
|
||||
//Check if the Author Name switch is enabled and appropriately handle the author name usage
|
||||
SwitchPreference useAuthorName = (SwitchPreference) findPreference("useAuthorName");
|
||||
|
|
@ -117,7 +116,7 @@ public class SettingsFragment extends PreferenceFragment {
|
|||
}
|
||||
});
|
||||
|
||||
listPreference = (ListPreference) findPreference("descriptionDefaultLanguagePref");
|
||||
langListPreference = (ListPreference) findPreference("descriptionDefaultLanguagePref");
|
||||
prepareLanguages();
|
||||
Preference betaTesterPreference = findPreference("becomeBetaTester");
|
||||
betaTesterPreference.setOnPreferenceClickListener(preference -> {
|
||||
|
|
@ -144,10 +143,32 @@ public class SettingsFragment extends PreferenceFragment {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses previously saved theme if there is any, if not then uses default.
|
||||
*/
|
||||
private void prepareTheme() {
|
||||
|
||||
themeListPreference.setSummary(getThemeSummary(getCurrentTheme()));
|
||||
|
||||
themeListPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
getActivity().recreate();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private CharSequence getThemeSummary(String value) {
|
||||
int prefIndex = themeListPreference.findIndexOfValue(value);
|
||||
return themeListPreference.getEntries()[prefIndex];
|
||||
}
|
||||
|
||||
private String getCurrentTheme() {
|
||||
return defaultKvStore.getString(Prefs.KEY_THEME_VALUE, THEME_MODE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares language summary and language codes list and adds them to list preference as pairs.
|
||||
* Uses previously saved language if there is any, if not uses phone local as initial language.
|
||||
* Adds preference changed listener and saves value choosen by user to shared preferences
|
||||
* Adds preference changed listener and saves value chosen by user to shared preferences
|
||||
* to remember later
|
||||
*/
|
||||
private void prepareLanguages() {
|
||||
|
|
@ -167,26 +188,26 @@ public class SettingsFragment extends PreferenceFragment {
|
|||
CharSequence[] languageNames = languageNamesList.toArray(new CharSequence[0]);
|
||||
CharSequence[] languageCodes = languageCodesList.toArray(new CharSequence[0]);
|
||||
// Add all languages and languages codes to lists preference as pair
|
||||
listPreference.setEntries(languageNames);
|
||||
listPreference.setEntryValues(languageCodes);
|
||||
langListPreference.setEntries(languageNames);
|
||||
langListPreference.setEntryValues(languageCodes);
|
||||
|
||||
// Gets current language code from shared preferences
|
||||
String languageCode = getCurrentLanguageCode();
|
||||
if(languageCode.equals("")){
|
||||
if (languageCode.equals("")){
|
||||
// If current language code is empty, means none selected by user yet so use phone local
|
||||
listPreference.setSummary(Locale.getDefault().getDisplayLanguage());
|
||||
listPreference.setValue(Locale.getDefault().getLanguage());
|
||||
langListPreference.setSummary(Locale.getDefault().getDisplayLanguage());
|
||||
langListPreference.setValue(Locale.getDefault().getLanguage());
|
||||
} else {
|
||||
// If any language is selected by user previously, use it
|
||||
int prefIndex = listPreference.findIndexOfValue(languageCode);
|
||||
listPreference.setSummary(listPreference.getEntries()[prefIndex]);
|
||||
listPreference.setValue(languageCode);
|
||||
int prefIndex = langListPreference.findIndexOfValue(languageCode);
|
||||
langListPreference.setSummary(langListPreference.getEntries()[prefIndex]);
|
||||
langListPreference.setValue(languageCode);
|
||||
}
|
||||
|
||||
listPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
langListPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String userSelectedValue = (String) newValue;
|
||||
int prefIndex = listPreference.findIndexOfValue(userSelectedValue);
|
||||
listPreference.setSummary(listPreference.getEntries()[prefIndex]);
|
||||
int prefIndex = langListPreference.findIndexOfValue(userSelectedValue);
|
||||
langListPreference.setSummary(langListPreference.getEntries()[prefIndex]);
|
||||
saveLanguageValue(userSelectedValue);
|
||||
return true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import javax.inject.Named;
|
|||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
public abstract class BaseActivity extends CommonsDaggerAppCompatActivity {
|
||||
|
|
@ -15,20 +16,23 @@ public abstract class BaseActivity extends CommonsDaggerAppCompatActivity {
|
|||
@Named("default_preferences")
|
||||
public JsonKvStore defaultKvStore;
|
||||
|
||||
@Inject
|
||||
SystemThemeUtils systemThemeUtils;
|
||||
|
||||
protected CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
protected boolean wasPreviouslyDarkTheme;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
wasPreviouslyDarkTheme = defaultKvStore.getBoolean("theme", false);
|
||||
wasPreviouslyDarkTheme = systemThemeUtils.isDeviceInNightMode();
|
||||
setTheme(wasPreviouslyDarkTheme ? R.style.DarkAppTheme : R.style.LightAppTheme);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
// Restart activity if theme is changed
|
||||
if (wasPreviouslyDarkTheme != defaultKvStore.getBoolean("theme", false)) {
|
||||
if (wasPreviouslyDarkTheme != systemThemeUtils.isDeviceInNightMode()) {
|
||||
recreate();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
|
||||
public class SystemThemeUtils {
|
||||
|
||||
private Context context;
|
||||
private JsonKvStore applicationKvStore;
|
||||
|
||||
public static final String THEME_MODE_DEFAULT = "0";
|
||||
public static final String THEME_MODE_DARK = "1";
|
||||
public static final String THEME_MODE_LIGHT = "2";
|
||||
|
||||
@Inject
|
||||
public SystemThemeUtils(Context context, @Named("default_preferences") JsonKvStore applicationKvStore) {
|
||||
this.context = context;
|
||||
this.applicationKvStore = applicationKvStore;
|
||||
}
|
||||
|
||||
// Return true is system wide dark theme is enabled else false
|
||||
public boolean getSystemDefaultThemeBool(String theme) {
|
||||
if (theme.equals(THEME_MODE_DARK)) {
|
||||
return true;
|
||||
} else if (theme.equals(THEME_MODE_DEFAULT)) {
|
||||
return getSystemDefaultThemeBool(getSystemDefaultTheme());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns the default system wide theme
|
||||
public String getSystemDefaultTheme() {
|
||||
return (context.getResources().getConfiguration().uiMode &
|
||||
Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES ? THEME_MODE_DARK : THEME_MODE_LIGHT;
|
||||
}
|
||||
|
||||
// Returns true if the device is in night mode or false otherwise
|
||||
public boolean isDeviceInNightMode() {
|
||||
return getSystemDefaultThemeBool(
|
||||
applicationKvStore.getString(Prefs.KEY_THEME_VALUE, getSystemDefaultTheme()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,4 +35,15 @@
|
|||
<item>@string/exif_tag_software</item>
|
||||
</array>
|
||||
|
||||
<array name="pref_theme_entries">
|
||||
<item>@string/theme_default_name</item>
|
||||
<item>@string/theme_dark_name</item>
|
||||
<item>@string/theme_light_name</item>
|
||||
</array>
|
||||
|
||||
<string-array name="pref_theme_entries_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
@ -113,8 +113,7 @@
|
|||
<string name="use_previous">Use previous title and description</string>
|
||||
<string name="allow_gps">Automatically get current location</string>
|
||||
<string name="allow_gps_summary">Retrieves current location if image is not geotagged, and geotags image with it. Warning: This will reveal your current location.</string>
|
||||
<string name="preference_theme">Night mode</string>
|
||||
<string name="preference_theme_summary">Use dark theme</string>
|
||||
<string name="preference_theme">Theme</string>
|
||||
<string name="license_name_cc_by_sa_four"> Attribution-ShareAlike 4.0</string>
|
||||
<string name="license_name_cc_by_four"> Attribution 4.0</string>
|
||||
<string name="license_name_cc_by_sa"> Attribution-ShareAlike 3.0</string>
|
||||
|
|
@ -599,4 +598,7 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="wallpaper_set_unsuccessfully">Something went wrong. Could not set the wallpaper</string>
|
||||
<string name="setting_wallpaper_dialog_title">Set as Wallpaper</string>
|
||||
<string name="setting_wallpaper_dialog_message">Setting Wallpaper. Please wait…</string>
|
||||
<string name="theme_default_name">Default</string>
|
||||
<string name="theme_dark_name">Dark</string>
|
||||
<string name="theme_light_name">Light</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory
|
||||
android:title="@string/preference_category_appearance">
|
||||
|
||||
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleSwitchPreference
|
||||
android:title="@string/preference_theme"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/preference_theme_summary"
|
||||
android:key="theme" />
|
||||
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleListPreference
|
||||
android:key="appThemePref"
|
||||
android:title= "@string/preference_theme"
|
||||
android:entries="@array/pref_theme_entries"
|
||||
android:entryValues="@array/pref_theme_entries_values"
|
||||
android:defaultValue="0"
|
||||
android:summary="@string/theme_default_name" />
|
||||
|
||||
</fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue