Fixes previous PR - FIX #2918 Add option for default language for file descriptions (#3020)

* FIX #2918 Add option for default language for file descriptions

* navigation menu error fixed and improvement of code quality

* error language description default fixed

* adapter language selected fixed

* local language selected per default in description language

* Use a better string and variable name as required in review 1

* Add comments

* Add previously missing setValue methods so that list item will be chosen along with the summary

* Add missing Javadocs

* Fix capitalization

* Lint and formatting issues

* Rename methods so it's clearer they are to do with languages

* Use default kv store instead of shared preferences variable

* Make sure saved language code from settings activity is handled on init
This commit is contained in:
neslihanturan 2019-06-24 14:40:12 +03:00 committed by Josephine Lim
parent 2837748540
commit dd50e83319
8 changed files with 150 additions and 29 deletions

View file

@ -8,6 +8,7 @@ public class Prefs {
public static final String UPLOADS_SHOWING = "uploadsshowing"; public static final String UPLOADS_SHOWING = "uploadsshowing";
public static final String IS_CONTRIBUTION_COUNT_CHANGED = "ccontributionCountChanged"; public static final String IS_CONTRIBUTION_COUNT_CHANGED = "ccontributionCountChanged";
public static final String MANAGED_EXIF_TAGS = "managedExifTags"; public static final String MANAGED_EXIF_TAGS = "managedExifTags";
public static final String KEY_LANGUAGE_VALUE = "languageDescription";
public static class Licenses { public static class Licenses {
public static final String CC_BY_SA_3 = "CC BY-SA 3.0"; public static final String CC_BY_SA_3 = "CC BY-SA 3.0";

View file

@ -1,12 +1,15 @@
package fr.free.nrw.commons.settings; package fr.free.nrw.commons.settings;
import android.Manifest; import android.Manifest;
import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.MultiSelectListPreference; import android.preference.MultiSelectListPreference;
import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
@ -15,10 +18,10 @@ import com.karumi.dexter.Dexter;
import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.single.BasePermissionListener; import com.karumi.dexter.listener.single.BasePermissionListener;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.ArrayList;
import java.util.Set; import java.util.List;
import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -30,6 +33,7 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.logging.CommonsLogSender; import fr.free.nrw.commons.logging.CommonsLogSender;
import fr.free.nrw.commons.utils.PermissionUtils; import fr.free.nrw.commons.utils.PermissionUtils;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.upload.Language;
public class SettingsFragment extends PreferenceFragment { public class SettingsFragment extends PreferenceFragment {
@ -38,6 +42,7 @@ public class SettingsFragment extends PreferenceFragment {
JsonKvStore defaultKvStore; JsonKvStore defaultKvStore;
@Inject @Inject
CommonsLogSender commonsLogSender; CommonsLogSender commonsLogSender;
private ListPreference listPreference;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -108,6 +113,8 @@ public class SettingsFragment extends PreferenceFragment {
} }
}); });
listPreference = (ListPreference) findPreference("descriptionDefaultLanguagePref");
prepareLanguages();
Preference betaTesterPreference = findPreference("becomeBetaTester"); Preference betaTesterPreference = findPreference("becomeBetaTester");
betaTesterPreference.setOnPreferenceClickListener(preference -> { betaTesterPreference.setOnPreferenceClickListener(preference -> {
Utils.handleWebUrl(getActivity(), Uri.parse(getResources().getString(R.string.beta_opt_in_link))); Utils.handleWebUrl(getActivity(), Uri.parse(getResources().getString(R.string.beta_opt_in_link)));
@ -133,6 +140,74 @@ public class SettingsFragment extends PreferenceFragment {
} }
} }
/**
* 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
* to remember later
*/
private void prepareLanguages() {
List<String> languageNamesList = new ArrayList<>();
List<String> languageCodesList = new ArrayList<>();
List<Language> languages = getLanguagesSupportedByDevice();
for(Language language: languages) {
// Go through all languages and add them to lists
if(!languageCodesList.contains(language.getLocale().getLanguage())) {
// This if prevents us from adding same language twice
languageNamesList.add(language.getLocale().getDisplayName());
languageCodesList.add(language.getLocale().getLanguage());
}
}
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);
// Gets current language code from shared preferences
String languageCode = getCurrentLanguageCode();
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());
} else {
// If any language is selected by user previously, use it
int prefIndex = listPreference.findIndexOfValue(languageCode);
listPreference.setSummary(listPreference.getEntries()[prefIndex]);
listPreference.setValue(languageCode);
}
listPreference.setOnPreferenceChangeListener((preference, newValue) -> {
String userSelectedValue = (String) newValue;
int prefIndex = listPreference.findIndexOfValue(userSelectedValue);
listPreference.setSummary(listPreference.getEntries()[prefIndex]);
saveLanguageValue(userSelectedValue);
return true;
});
}
private void saveLanguageValue(String userSelectedValue) {
defaultKvStore.putString(Prefs.KEY_LANGUAGE_VALUE, userSelectedValue);
}
private String getCurrentLanguageCode() {
return defaultKvStore.getString(Prefs.KEY_LANGUAGE_VALUE, "");
}
private List<Language> getLanguagesSupportedByDevice() {
List<Language> languages = new ArrayList<>();
Locale[] localesArray = Locale.getAvailableLocales();
for (Locale locale : localesArray) {
languages.add(new Language(locale));
}
Collections.sort(languages, (language, t1) -> language.getLocale().getDisplayName()
.compareTo(t1.getLocale().getDisplayName()));
return languages;
}
/** /**
* First checks for external storage permissions and then sends logs via email * First checks for external storage permissions and then sends logs via email
*/ */

View file

@ -32,10 +32,12 @@ public class DescriptionsAdapter extends RecyclerView.Adapter<DescriptionsAdapte
private Callback callback; private Callback callback;
private BiMap<AdapterView, String> selectedLanguages; private BiMap<AdapterView, String> selectedLanguages;
private String savedLanguageValue;
public DescriptionsAdapter() { public DescriptionsAdapter(String savedLanguageValue) {
descriptions = new ArrayList<>(); descriptions = new ArrayList<>();
selectedLanguages = new BiMap<>(); selectedLanguages = new BiMap<>();
this.savedLanguageValue = savedLanguageValue;
} }
public void setCallback(Callback callback) { public void setCallback(Callback callback) {
@ -143,7 +145,8 @@ public class DescriptionsAdapter extends RecyclerView.Adapter<DescriptionsAdapte
private void initLanguageSpinner(int position, Description description) { private void initLanguageSpinner(int position, Description description) {
SpinnerLanguagesAdapter languagesAdapter = new SpinnerLanguagesAdapter( SpinnerLanguagesAdapter languagesAdapter = new SpinnerLanguagesAdapter(
spinnerDescriptionLanguages.getContext(), spinnerDescriptionLanguages.getContext(),
R.layout.row_item_languages_spinner, selectedLanguages); R.layout.row_item_languages_spinner, selectedLanguages,
savedLanguageValue);
languagesAdapter.notifyDataSetChanged(); languagesAdapter.notifyDataSetChanged();
spinnerDescriptionLanguages.setAdapter(languagesAdapter); spinnerDescriptionLanguages.setAdapter(languagesAdapter);
@ -159,15 +162,19 @@ public class DescriptionsAdapter extends RecyclerView.Adapter<DescriptionsAdapte
selectedLanguages.put(adapterView, languageCode); selectedLanguages.put(adapterView, languageCode);
((SpinnerLanguagesAdapter) adapterView ((SpinnerLanguagesAdapter) adapterView
.getAdapter()).selectedLangCode = languageCode; .getAdapter()).selectedLangCode = languageCode;
Timber.d("Description language code is: "+languageCode);
} }
@Override @Override
public void onNothingSelected(AdapterView<?> adapterView) { public void onNothingSelected(AdapterView<?> adapterView) {
} }
}); });
if (description.getSelectedLanguageIndex() == -1) { if (description.getSelectedLanguageIndex() == -1) {
if (savedLanguageValue != null) {
// If user has chosen a default language from settings activity savedLanguageValue is not null
spinnerDescriptionLanguages.setSelection(languagesAdapter.getIndexOfLanguageCode(savedLanguageValue));
} else {
if (position == 0) { if (position == 0) {
int defaultLocaleIndex = languagesAdapter int defaultLocaleIndex = languagesAdapter
.getIndexOfUserDefaultLocale(spinnerDescriptionLanguages.getContext()); .getIndexOfUserDefaultLocale(spinnerDescriptionLanguages.getContext());
@ -175,6 +182,8 @@ public class DescriptionsAdapter extends RecyclerView.Adapter<DescriptionsAdapte
} else { } else {
spinnerDescriptionLanguages.setSelection(0); spinnerDescriptionLanguages.setSelection(0);
} }
}
} else { } else {
spinnerDescriptionLanguages.setSelection(description.getSelectedLanguageIndex()); spinnerDescriptionLanguages.setSelection(description.getSelectedLanguageIndex());
selectedLanguages.put(spinnerDescriptionLanguages, description.getLanguageCode()); selectedLanguages.put(spinnerDescriptionLanguages, description.getLanguageCode());

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.upload;
import java.util.Locale; import java.util.Locale;
class Language { public class Language {
private Locale locale; private Locale locale;
private boolean isSet = false; private boolean isSet = false;

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons.upload; package fr.free.nrw.commons.upload;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color; import android.graphics.Color;
import android.preference.PreferenceManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -16,15 +18,16 @@ import java.util.Locale;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.utils.BiMap; import fr.free.nrw.commons.utils.BiMap;
import fr.free.nrw.commons.utils.LangCodeUtils; import fr.free.nrw.commons.utils.LangCodeUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public class SpinnerLanguagesAdapter extends ArrayAdapter { public class SpinnerLanguagesAdapter extends ArrayAdapter {
@ -34,11 +37,16 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
private List<String> languageCodesList; private List<String> languageCodesList;
private final BiMap<AdapterView, String> selectedLanguages; private final BiMap<AdapterView, String> selectedLanguages;
public String selectedLangCode=""; public String selectedLangCode="";
private Context context;
private boolean dropDownClicked;
private String savedLanguageValue;
public SpinnerLanguagesAdapter(@NonNull Context context, public SpinnerLanguagesAdapter(@NonNull Context context,
int resource, BiMap<AdapterView, String> selectedLanguages) { int resource,
BiMap<AdapterView, String> selectedLanguages,
String savedLanguageValue) {
super(context, resource); super(context, resource);
this.resource = resource; this.resource = resource;
this.layoutInflater = LayoutInflater.from(context); this.layoutInflater = LayoutInflater.from(context);
@ -46,6 +54,9 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
languageCodesList = new ArrayList<>(); languageCodesList = new ArrayList<>();
prepareLanguages(); prepareLanguages();
this.selectedLanguages = selectedLanguages; this.selectedLanguages = selectedLanguages;
this.context = context;
this.dropDownClicked = false;
this.savedLanguageValue = savedLanguageValue;
} }
private void prepareLanguages() { private void prepareLanguages() {
@ -90,7 +101,9 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
convertView = layoutInflater.inflate(resource, parent, false); convertView = layoutInflater.inflate(resource, parent, false);
} }
ViewHolder holder = new ViewHolder(convertView); ViewHolder holder = new ViewHolder(convertView);
holder.init(position, true); holder.init(position, true, savedLanguageValue);
dropDownClicked = true;
return convertView; return convertView;
} }
@ -105,7 +118,7 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
} else { } else {
holder = (ViewHolder) convertView.getTag(); holder = (ViewHolder) convertView.getTag();
} }
holder.init(position, false); holder.init(position, false, savedLanguageValue);
return convertView; return convertView;
} }
@ -122,17 +135,23 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
} }
public void init(int position, boolean isDropDownView) { public void init(int position, boolean isDropDownView, String savedLanguageValue) {
final String languageCode = LangCodeUtils.fixLanguageCode(languageCodesList.get(position)); String languageCode = LangCodeUtils.fixLanguageCode(languageCodesList.get(position));
final String languageName = String.format("%s%s", languageNamesList.get(position) final String languageName = StringUtils.capitalize(languageNamesList.get(position));
.substring(0, 1).toUpperCase(), languageNamesList.get(position).substring(1));
if(savedLanguageValue.equals("")){
savedLanguageValue = Locale.getDefault().getLanguage();
}
if (!isDropDownView) { if (!isDropDownView) {
if( !dropDownClicked){
languageCode = LangCodeUtils.fixLanguageCode(savedLanguageValue);
}
view.setVisibility(View.GONE); view.setVisibility(View.GONE);
if (languageCode.length() > 2) if (languageCode.length() > 2)
tvLanguage.setText(languageCode.subSequence(0,2)); tvLanguage.setText(languageCode.substring(0, 2));
else else
tvLanguage.setText(languageCode); tvLanguage.setText(languageCode);
} else { } else {
view.setVisibility(View.VISIBLE); view.setVisibility(View.VISIBLE);
if (languageCodesList.get(position).isEmpty()) { if (languageCodesList.get(position).isEmpty()) {
@ -158,4 +177,7 @@ public class SpinnerLanguagesAdapter extends ArrayAdapter {
return languageCodesList.indexOf(context.getResources().getConfiguration().locale.getLanguage()); return languageCodesList.indexOf(context.getResources().getConfiguration().locale.getLanguage());
} }
int getIndexOfLanguageCode(String languageCode) {
return languageCodesList.indexOf(languageCode);
}
} }

View file

@ -32,6 +32,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
@ -39,8 +40,10 @@ import butterknife.OnClick;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.filepicker.UploadableFile; import fr.free.nrw.commons.filepicker.UploadableFile;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.Place; import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.Description; import fr.free.nrw.commons.upload.Description;
import fr.free.nrw.commons.upload.DescriptionsAdapter; import fr.free.nrw.commons.upload.DescriptionsAdapter;
import fr.free.nrw.commons.upload.SimilarImageDialogFragment; import fr.free.nrw.commons.upload.SimilarImageDialogFragment;
@ -86,6 +89,11 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@Inject @Inject
UploadMediaDetailsContract.UserActionListener presenter; UploadMediaDetailsContract.UserActionListener presenter;
@Inject
@Named("default_preferences")
JsonKvStore defaultKvStore;
private UploadableFile uploadableFile; private UploadableFile uploadableFile;
private String source; private String source;
private Place place; private Place place;
@ -214,7 +222,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
* init the recycler veiw * init the recycler veiw
*/ */
private void initRecyclerView() { private void initRecyclerView() {
descriptionsAdapter = new DescriptionsAdapter(); descriptionsAdapter = new DescriptionsAdapter(defaultKvStore.getString(Prefs.KEY_LANGUAGE_VALUE,""));
descriptionsAdapter.setCallback(this::showInfoAlert); descriptionsAdapter.setCallback(this::showInfoAlert);
rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext())); rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext()));
rvDescriptions.setAdapter(descriptionsAdapter); rvDescriptions.setAdapter(descriptionsAdapter);

View file

@ -558,4 +558,5 @@ Upload your first media by tapping on the add button.</string>
<string name="upload_cancelled">Cancelled Upload</string> <string name="upload_cancelled">Cancelled Upload</string>
<string name="previous_image_title_description_not_found">There is no data for previous image\'s title or description</string> <string name="previous_image_title_description_not_found">There is no data for previous image\'s title or description</string>
<string name="dialog_box_text_nomination">Why should %1$s be deleted?</string> <string name="dialog_box_text_nomination">Why should %1$s be deleted?</string>
<string name="default_description_language">Default description language</string>
</resources> </resources>

View file

@ -29,6 +29,11 @@
android:inputType="number" android:inputType="number"
android:maxLength="3" /> android:maxLength="3" />
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleListPreference
android:key="descriptionDefaultLanguagePref"
android:title= "@string/default_description_language"
android:summary="English" />
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleSwitchPreference <fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleSwitchPreference
android:key="useAuthorName" android:key="useAuthorName"
android:title="@string/preference_author_name_toggle" android:title="@string/preference_author_name_toggle"