Feature/localised image descriptions (#1634)

* wip

* Changes for adding descriptions in multipe languages[issue #1501]

* Added callback for the adapter

* Codacy suggested changes

* Sort the languages in the spinner in alphabetical order

* scroll view nested scrolling enabled false

* Nested scrolling enabled false [Allow rv to expand]

* rebased to master, resolved conflicts

* replaced setCompoundDrawables with setCompoundDrawablesWithIntrinsicBounds [the former dint used to work on all devices]

*     replaced setCompoundDrawables with setCompoundDrawablesWithIntrinsicBounds [the former dint used to work on all devices]
This commit is contained in:
Ashish Kumar 2018-08-03 18:09:37 +05:30 committed by Vivek Maskara
parent e4c518ccce
commit 12a83da3a2
12 changed files with 622 additions and 122 deletions

View file

@ -13,7 +13,7 @@ import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.settings.Prefs; import fr.free.nrw.commons.settings.Prefs;
public class Contribution extends Media { public class Contribution extends Media {
public static Creator<Contribution> CREATOR = new Creator<Contribution>() { public static Creator<Contribution> CREATOR = new Creator<Contribution>() {
@Override @Override

View file

@ -60,6 +60,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
private boolean isCategoryImage; private boolean isCategoryImage;
private MediaDetailPagerFragment.MediaDetailProvider detailProvider; private MediaDetailPagerFragment.MediaDetailProvider detailProvider;
private int index; private int index;
private Locale locale;
public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage) { public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage) {
MediaDetailFragment mf = new MediaDetailFragment(); MediaDetailFragment mf = new MediaDetailFragment();
@ -198,6 +199,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
} }
}; };
view.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener); view.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
locale = getResources().getConfiguration().locale;
return view; return view;
} }
@ -455,7 +457,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
private String prettyDescription(Media media) { private String prettyDescription(Media media) {
// @todo use UI language when multilingual descs are available // @todo use UI language when multilingual descs are available
String desc = media.getDescription("en").trim(); String desc = media.getDescription(locale.getLanguage()).trim();
if (desc.equals("")) { if (desc.equals("")) {
return getString(R.string.detail_description_empty); return getString(R.string.detail_description_empty);
} else { } else {

View file

@ -0,0 +1,57 @@
package fr.free.nrw.commons.upload;
import android.text.TextUtils;
import android.util.TimeUtils;
class Description {
private String languageId;
private String languageDisplayText;
private String descriptionText;
private boolean set;
private int selectedLanguageIndex = -1;
public String getLanguageId() {
return languageId;
}
public void setLanguageId(String languageId) {
this.languageId = languageId;
}
public String getLanguageDisplayText() {
return languageDisplayText;
}
public void setLanguageDisplayText(String languageDisplayText) {
this.languageDisplayText = languageDisplayText;
}
public String getDescriptionText() {
return descriptionText;
}
public void setDescriptionText(String descriptionText) {
this.descriptionText = descriptionText;
if (!TextUtils.isEmpty(descriptionText)) {
set = true;
}
}
public boolean isSet() {
return set;
}
public void setSet(boolean set) {
this.set = set;
}
public int getSelectedLanguageIndex() {
return selectedLanguageIndex;
}
public void setSelectedLanguageIndex(int selectedLanguageIndex) {
this.selectedLanguageIndex = selectedLanguageIndex;
}
}

View file

@ -0,0 +1,231 @@
package fr.free.nrw.commons.upload;
import static android.view.MotionEvent.ACTION_UP;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.EditText;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnTouch;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.utils.ViewUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
class DescriptionsAdapter extends RecyclerView.Adapter<DescriptionsAdapter.ViewHolder> {
List<Description> descriptions;
List<Language> languages;
private Context context;
private Callback callback;
public DescriptionsAdapter() {
descriptions = new ArrayList<>();
descriptions.add(new Description());
languages = new ArrayList<>();
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public void setDescriptions(List<Description> descriptions) {
this.descriptions = descriptions;
notifyDataSetChanged();
}
public void setLanguages(List<Language> languages) {
this.languages = languages;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_item_description, parent, false);
context = parent.getContext();
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.init(position);
}
@Override
public int getItemCount() {
return descriptions.size();
}
public List<Description> getDescriptions() {
return descriptions;
}
public void addDescription(Description description) {
this.descriptions.add(description);
notifyItemInserted(descriptions.size() - 1);
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.spinner_description_languages)
AppCompatSpinner spinnerDescriptionLanguages;
@BindView(R.id.et_description_text)
EditText etDescriptionText;
private View view;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
this.view = itemView;
}
public void init(int position) {
Description description = descriptions.get(position);
if (!TextUtils.isEmpty(description.getDescriptionText())) {
etDescriptionText.setText(description.getDescriptionText());
} else {
etDescriptionText.setText("");
}
Drawable drawableRight = context.getResources()
.getDrawable(R.drawable.mapbox_info_icon_default);
if (position != 0) {
etDescriptionText.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
} else {
etDescriptionText.setCompoundDrawablesWithIntrinsicBounds(null, null, drawableRight, null);
}
etDescriptionText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
description.setDescriptionText(editable.toString());
}
});
etDescriptionText.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
ViewUtil.hideKeyboard(v);
}
});
SpinnerLanguagesAdapter languagesAdapter = new SpinnerLanguagesAdapter(context,
R.layout.row_item_languages_spinner);
Collections.sort(languages, (language, t1) -> language.getLocale().getDisplayLanguage()
.compareTo(t1.getLocale().getDisplayLanguage().toString()));
languagesAdapter.setLanguages(languages);
languagesAdapter.notifyDataSetChanged();
spinnerDescriptionLanguages.setAdapter(languagesAdapter);
if (description.getSelectedLanguageIndex() == -1) {
if (position == 0) {
int defaultLocaleIndex = getIndexOfUserDefaultLocale();
spinnerDescriptionLanguages.setSelection(defaultLocaleIndex);
} else {
spinnerDescriptionLanguages.setSelection(0);
}
} else {
spinnerDescriptionLanguages.setSelection(description.getSelectedLanguageIndex());
}
languages.get(spinnerDescriptionLanguages.getSelectedItemPosition()).setSet(true);
//TODO do it the butterknife way
spinnerDescriptionLanguages.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position,
long l) {
//TODO handle case when user tries to select an already selected language
updateDescriptionBasedOnSelectedLanguageIndex(description, position);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
@OnTouch(R.id.et_description_text)
boolean descriptionInfo(View view, MotionEvent motionEvent) {
if (getAdapterPosition() == 0) {
//Description info is visible only for the first item
final int value;
if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) {
value = etDescriptionText.getRight() - etDescriptionText
.getCompoundDrawables()[2]
.getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
callback.showAlert(R.string.media_detail_description,
R.string.description_info);
return true;
}
} else {
value = etDescriptionText.getLeft() + etDescriptionText
.getCompoundDrawables()[0]
.getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() <= value) {
callback.showAlert(R.string.media_detail_description,
R.string.description_info);
return true;
}
}
}
return false;
}
}
private int getIndexOfUserDefaultLocale() {
for (int i = 0; i < languages.size(); i++) {
if (languages.get(i).getLocale()
.equals(context.getResources().getConfiguration().locale)) {
return i;
}
}
return 0;
}
private void updateDescriptionBasedOnSelectedLanguageIndex(Description description,
int position) {
Language language = languages.get(position);
Locale locale = language.getLocale();
description.setSelectedLanguageIndex(position);
description.setLanguageDisplayText(locale.getDisplayName());
description.setLanguageId(locale.getLanguage());
}
public interface Callback {
void showAlert(int mediaDetailDescription, int descriptionInfo);
}
}

View file

@ -0,0 +1,29 @@
package fr.free.nrw.commons.upload;
import java.util.Locale;
class Language {
private Locale locale;
private boolean isSet = false;
public Language(Locale locale) {
this.locale = locale;
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public boolean isSet() {
return isSet;
}
public void setSet(boolean set) {
isSet = set;
}
}

View file

@ -481,7 +481,7 @@ public class ShareActivity
CurrentAnimator.cancel(); CurrentAnimator.cancel();
} }
isZoom = true; isZoom = true;
ViewUtil.hideKeyboard(ShareActivity.this.findViewById(R.id.titleEdit | R.id.descEdit)); ViewUtil.hideKeyboard(ShareActivity.this.findViewById(R.id.titleEdit));
closeFABMenu(); closeFABMenu();
mainFab.setVisibility(View.GONE); mainFab.setVisibility(View.GONE);

View file

@ -10,6 +10,8 @@ import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.text.Html; import android.text.Html;
import android.text.TextWatcher; import android.text.TextWatcher;
@ -30,9 +32,16 @@ import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import fr.free.nrw.commons.upload.DescriptionsAdapter.Callback;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -53,7 +62,7 @@ import static android.view.MotionEvent.ACTION_UP;
public class SingleUploadFragment extends CommonsDaggerSupportFragment { public class SingleUploadFragment extends CommonsDaggerSupportFragment {
@BindView(R.id.titleEdit) EditText titleEdit; @BindView(R.id.titleEdit) EditText titleEdit;
@BindView(R.id.descEdit) EditText descEdit; @BindView(R.id.rv_descriptions) RecyclerView rvDescriptions;
@BindView(R.id.titleDescButton) Button titleDescButton; @BindView(R.id.titleDescButton) Button titleDescButton;
@BindView(R.id.share_license_summary) TextView licenseSummaryView; @BindView(R.id.share_license_summary) TextView licenseSummaryView;
@BindView(R.id.licenseSpinner) Spinner licenseSpinner; @BindView(R.id.licenseSpinner) Spinner licenseSpinner;
@ -65,6 +74,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
private String license; private String license;
private OnUploadActionInitiated uploadActionInitiatedHandler; private OnUploadActionInitiated uploadActionInitiatedHandler;
private TitleTextWatcher textWatcher = new TitleTextWatcher(); private TitleTextWatcher textWatcher = new TitleTextWatcher();
private DescriptionsAdapter descriptionsAdapter;
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
@ -82,35 +92,60 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
return false; return false;
} }
String title = titleEdit.getText().toString().trim(); String title = titleEdit.getText().toString();
String desc = descEdit.getText().toString().trim(); String descriptionsInVariousLanguages = getDescriptionsInAppropriateFormat();
//Save the title/desc in short-lived cache so next time this fragment is loaded, we can access these //Save the title/desc in short-lived cache so next time this fragment is loaded, we can access these
prefs.edit() prefs.edit()
.putString("Title", title) .putString("Title", title)
.putString("Desc", desc) .putString("Desc", new Gson().toJson(descriptionsAdapter
.getDescriptions()))//Description, now is not just a string, its a list of description objects
.apply(); .apply();
uploadActionInitiatedHandler.uploadActionInitiated(title, desc); uploadActionInitiatedHandler
.uploadActionInitiated(title, descriptionsInVariousLanguages);
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private String getDescriptionsInAppropriateFormat() {
List<Description> descriptions = descriptionsAdapter.getDescriptions();
StringBuilder descriptionsInAppropriateFormat = new StringBuilder();
for (Description description : descriptions) {
String individualDescription = String.format("{{%s|1=%s}}", description.getLanguageId(),
description.getDescriptionText());
descriptionsInAppropriateFormat.append(individualDescription);
}
return descriptionsInAppropriateFormat.toString();
}
private List<Description> getDescriptions() {
List<Description> descriptions = descriptionsAdapter.getDescriptions();
return descriptions;
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_single_upload, container, false); View rootView = inflater.inflate(R.layout.fragment_single_upload, container, false);
ButterKnife.bind(this, rootView); ButterKnife.bind(this, rootView);
initRecyclerView();
Intent activityIntent = getActivity().getIntent(); Intent activityIntent = getActivity().getIntent();
if (activityIntent.hasExtra("title")) { if (activityIntent.hasExtra("title")) {
titleEdit.setText(activityIntent.getStringExtra("title")); titleEdit.setText(activityIntent.getStringExtra("title"));
} }
if (activityIntent.hasExtra("description")) { if (activityIntent.hasExtra("description") && descriptionsAdapter.getDescriptions() != null
descEdit.setText(activityIntent.getStringExtra("description")); && descriptionsAdapter.getDescriptions().size() > 0) {
descriptionsAdapter.getDescriptions().get(0)
.setDescriptionText(activityIntent.getStringExtra("description"));
descriptionsAdapter.notifyItemChanged(0);
} }
ArrayList<String> licenseItems = new ArrayList<>(); ArrayList<String> licenseItems = new ArrayList<>();
licenseItems.add(getString(R.string.license_name_cc0)); licenseItems.add(getString(R.string.license_name_cc0));
licenseItems.add(getString(R.string.license_name_cc_by)); licenseItems.add(getString(R.string.license_name_cc_by));
@ -129,7 +164,11 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
String imageCats = directPrefs.getString("Category", ""); String imageCats = directPrefs.getString("Category", "");
Timber.d("Image title: " + imageTitle + ", image desc: " + imageDesc + ", image categories: " + imageCats); Timber.d("Image title: " + imageTitle + ", image desc: " + imageDesc + ", image categories: " + imageCats);
titleEdit.setText(imageTitle); titleEdit.setText(imageTitle);
descEdit.setText(imageDesc); if (descriptionsAdapter.getDescriptions() != null
&& descriptionsAdapter.getDescriptions().size() > 0) {
descriptionsAdapter.getDescriptions().get(0).setDescriptionText(imageDesc);
descriptionsAdapter.notifyItemChanged(0);
}
} }
// check if this is the first time we have uploaded // check if this is the first time we have uploaded
@ -170,17 +209,29 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
} }
}); });
descEdit.setOnFocusChangeListener((v, hasFocus) -> {
if(!hasFocus){
ViewUtil.hideKeyboard(v);
}
});
setLicenseSummary(license); setLicenseSummary(license);
return rootView; return rootView;
} }
private void initRecyclerView() {
descriptionsAdapter = new DescriptionsAdapter();
descriptionsAdapter.setCallback((mediaDetailDescription, descriptionInfo) -> showInfoAlert(mediaDetailDescription,descriptionInfo));
descriptionsAdapter.setLanguages(getLocaleSupportedByDevice());
rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext()));
rvDescriptions.setAdapter(descriptionsAdapter);
}
private List<Language> getLocaleSupportedByDevice() {
List<Language> languages = new ArrayList<>();
Locale[] localesArray = Locale.getAvailableLocales();
List<Locale> locales = Arrays.asList(localesArray);
for (Locale locale : locales) {
languages.add(new Language(locale));
}
return languages;
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
titleEdit.removeTextChangedListener(textWatcher); titleEdit.removeTextChangedListener(textWatcher);
@ -224,11 +275,16 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
void setTitleDescButton() { void setTitleDescButton() {
//Retrieve last title and desc entered //Retrieve last title and desc entered
String title = prefs.getString("Title", ""); String title = prefs.getString("Title", "");
String desc = prefs.getString("Desc", ""); String descriptionJson = prefs.getString("Desc", "");
Timber.d("Title: %s, Desc: %s", title, desc); Timber.d("Title: %s, Desc: %s", title, descriptionJson);
titleEdit.setText(title); titleEdit.setText(title);
descEdit.setText(desc); Type typeOfDest = new TypeToken<List<Description>>() {
}.getType();
List<Description> descriptions = new Gson().fromJson(descriptionJson, typeOfDest);
descriptionsAdapter.setDescriptions(descriptions);
} }
/** /**
@ -254,26 +310,6 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
return false; return false;
} }
@OnTouch(R.id.descEdit)
boolean descriptionInfo(View view, MotionEvent motionEvent) {
final int value;
if (ViewCompat.getLayoutDirection(getView()) == ViewCompat.LAYOUT_DIRECTION_LTR) {
value = descEdit.getRight() - descEdit.getCompoundDrawables()[2].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
showInfoAlert(R.string.media_detail_description,R.string.description_info);
return true;
}
}
else{
value = descEdit.getLeft() + descEdit.getCompoundDrawables()[0].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() <= value) {
showInfoAlert(R.string.media_detail_description,R.string.description_info);
return true;
}
}
return false;
}
@SuppressLint("StringFormatInvalid") @SuppressLint("StringFormatInvalid")
private void setLicenseSummary(String license) { private void setLicenseSummary(String license) {
String licenseHyperLink = "<a href='" + licenseUrlFor(license)+"'>"+ getString(Utils.licenseNameFor(license)) + "</a><br>"; String licenseHyperLink = "<a href='" + licenseUrlFor(license)+"'>"+ getString(Utils.licenseNameFor(license)) + "</a><br>";
@ -315,10 +351,12 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
} }
public interface OnUploadActionInitiated { public interface OnUploadActionInitiated {
void uploadActionInitiated(String title, String description); void uploadActionInitiated(String title, String description);
} }
private class TitleTextWatcher implements TextWatcher { private class TitleTextWatcher implements TextWatcher {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
} }
@ -346,16 +384,9 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
.show(); .show();
} }
/** @OnClick(R.id.ll_add_description)
* To launch the Commons:Licensing public void onLLAddDescriptionClicked() {
* @param view descriptionsAdapter.addDescription(new Description());
*/ rvDescriptions.scrollToPosition(descriptionsAdapter.getItemCount() - 1);
@OnClick(R.id.licenseInfo)
public void launchLicenseInfo(View view){
Log.i("Language", Locale.getDefault().getLanguage());
UrlLicense urlLicense = new UrlLicense();
urlLicense.initialize();
String url = urlLicense.getLicenseUrl(Locale.getDefault().getLanguage());
Utils.handleWebUrl(getActivity() , Uri.parse(url));
} }
} }

View file

@ -0,0 +1,92 @@
package fr.free.nrw.commons.upload;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class SpinnerLanguagesAdapter extends ArrayAdapter {
private final int resource;
private final LayoutInflater layoutInflater;
List<Language> languages;
public SpinnerLanguagesAdapter(@NonNull Context context,
int resource) {
super(context, resource);
this.resource = resource;
this.layoutInflater = LayoutInflater.from(context);
languages = new ArrayList<>();
}
public void setLanguages(List<Language> languages) {
this.languages = languages;
}
@Override
public int getCount() {
return languages.size();
}
@Override
public View getDropDownView(int position, @Nullable View convertView,
@NonNull ViewGroup parent) {
View view = layoutInflater.inflate(resource, parent, false);
ViewHolder holder = new ViewHolder(view);
holder.init(position, true);
return view;
}
@Override
public @NonNull
View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View view = layoutInflater.inflate(resource, parent, false);
ViewHolder holder = new ViewHolder(view);
holder.init(position, false);
return view;
}
public class ViewHolder {
@BindView(R.id.ll_container_description_language)
LinearLayout llContainerDescriptionLanguage;
@BindView(R.id.tv_language)
TextView tvLanguage;
@BindView(R.id.view)
View view;
public ViewHolder(View itemView) {
ButterKnife.bind(this, itemView);
}
public void init(int position, boolean isDropDownView) {
Language language = languages.get(position);
if (!isDropDownView) {
view.setVisibility(View.GONE);
tvLanguage.setText(
language.getLocale().getLanguage());
} else {
view.setVisibility(View.VISIBLE);
tvLanguage.setText(
String.format("%s [%s]", language.getLocale().getDisplayName(),
language.getLocale().getLanguage()));
}
}
}
}

View file

@ -12,6 +12,7 @@
android:paddingRight="@dimen/standard_gap" android:paddingRight="@dimen/standard_gap"
android:paddingStart="@dimen/standard_gap" android:paddingStart="@dimen/standard_gap"
android:paddingTop="@dimen/small_gap" android:paddingTop="@dimen/small_gap"
android:nestedScrollingEnabled="false"
android:theme="@style/DarkAppTheme"> android:theme="@style/DarkAppTheme">
<LinearLayout <LinearLayout
@ -38,40 +39,36 @@
android:scrollHorizontally="false" /> android:scrollHorizontally="false" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/descEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableEnd="@drawable/mapbox_info_icon_default"
android:drawableRight="@drawable/mapbox_info_icon_default"
android:hint="@string/share_description_hint"
android:imeOptions="flagNoExtractUi"
android:inputType="textMultiLine" />
</android.support.design.widget.TextInputLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
<Spinner android:orientation="vertical">
android:id="@+id/licenseSpinner" <android.support.v7.widget.RecyclerView
android:layout_width="0dp" android:id="@+id/rv_descriptions"
android:layout_weight="15" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:theme="?attr/spinnerTheme" /> <LinearLayout
android:layout_marginTop="4dp"
android:orientation="horizontal"
android:id="@+id/ll_add_description"
android:layout_width="wrap_content"
android:layout_gravity="right"
android:gravity="right"
android:padding="10dp"
android:layout_height="wrap_content"
>
<TextView <TextView
android:layout_width="0dp" style="@style/TextAppearance.AppCompat.Body1"
android:layout_weight="1" android:text="@string/add_description"
android:id="@+id/licenseInfo" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:text="(?)" </LinearLayout>
android:textColor="@color/primaryTextColor"/>
</LinearLayout> </LinearLayout>
<Spinner
android:id="@+id/licenseSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/spinnerTheme" />
<Button <Button
android:id="@+id/titleDescButton" android:id="@+id/titleDescButton"

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="10">
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/spinner_description_languages"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:spinnerMode="dialog"></android.support.v7.widget.AppCompatSpinner>
<android.support.design.widget.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="7">
<EditText
android:id="@+id/et_description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableEnd="@drawable/mapbox_info_icon_default"
android:drawableRight="@drawable/mapbox_info_icon_default"
android:hint="@string/share_description_hint"
android:imeOptions="flagNoExtractUi"
android:inputType="textMultiLine"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:id="@+id/ll_container_description_language"
android:orientation="vertical">
<TextView
android:id="@+id/tv_language"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:imeOptions="flagNoExtractUi"
android:maxLines="1"
style="@style/Base.TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
android:singleLine="true"
tools:text="en"
/>
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/item_white_background"></View>
</LinearLayout>

View file

@ -248,50 +248,47 @@
<string name="nominated_see_more"><u>See webpage for details</u></string> <string name="nominated_see_more"><u>See webpage for details</u></string>
<string name="view_browser">View in Browser</string> <string name="view_browser">View in Browser</string>
<string name="nearby_location_has_not_changed">Location has not changed.</string> <string name="nearby_location_has_not_changed">Location has not changed.</string>
<string name="nearby_location_not_available">Location not available.</string> <string name="nearby_location_not_available">Location not available.</string>
<string name="location_permission_rationale_nearby">Permission required to display a list of nearby places</string> <string name="location_permission_rationale_nearby">Permission required to display a list of nearby places</string>
<string name="get_directions">GET DIRECTIONS</string> <string name="get_directions">GET DIRECTIONS</string>
<string name="read_article">READ ARTICLE</string> <string name="read_article">READ ARTICLE</string>
<string name="notifications_welcome" formatted="false">Welcome to Wikimedia Commons, %1$s! We\'re glad you\'re here.</string> <string formatted="false" name="notifications_welcome">Welcome to Wikimedia Commons, %1$s! We\'re glad you\'re here.</string>
<string name="notifications_talk_page_message">%1$s left a message on your talk page</string> <string name="notifications_talk_page_message">%1$s left a message on your talk page</string>
<string name="notifications_thank_you_edit">Thank you for making an edit</string> <string name="notifications_thank_you_edit">Thank you for making an edit</string>
<string name="notifications_mention">%1$s mentioned you on %2$s.</string> <string name="notifications_mention">%1$s mentioned you on %2$s.</string>
<string name="toggle_view_button">Toggle view</string> <string name="toggle_view_button">Toggle view</string>
<string name="nearby_directions">DIRECTIONS</string> <string name="nearby_directions">DIRECTIONS</string>
<string name="nearby_wikidata">WIKIDATA</string> <string name="nearby_wikidata">WIKIDATA</string>
<string name="nearby_wikipedia">WIKIPEDIA</string> <string name="nearby_wikipedia">WIKIPEDIA</string>
<string name="nearby_commons">COMMONS</string> <string name="nearby_commons">COMMONS</string>
<string name="about_rate_us"><![CDATA[<u>Rate us</u>]]></string> <string name="about_rate_us"><![CDATA[<u>Rate us</u>]]></string>
<string name="about_faq"><![CDATA[<u>FAQ</u>]]></string> <string name="about_faq"><![CDATA[<u>FAQ</u>]]></string>
<string name="welcome_skip_button">Skip Tutorial</string> <string name="welcome_skip_button">Skip Tutorial</string>
<string name="no_internet">Internet unavailable</string> <string name="no_internet">Internet unavailable</string>
<string name="internet_established">Internet available</string> <string name="internet_established">Internet available</string>
<string name="error_notifications">Error fetching notifications</string> <string name="error_notifications">Error fetching notifications</string>
<string name="no_notifications">No notifications found</string> <string name="no_notifications">No notifications found</string>
<string name="about_translate"><![CDATA[<u>Translate</u>]]></string> <string name="about_translate"><![CDATA[<u>Translate</u>]]></string>
<string name="about_translate_title">Languages</string> <string name="about_translate_title">Languages</string>
<string name="about_translate_message">Select the language that you would like to submit translations for</string> <string name="about_translate_message">Select the language that you would like to submit translations for</string>
<string name="about_translate_proceed">Proceed</string> <string name="about_translate_proceed">Proceed</string>
<string name="about_translate_cancel">Cancel</string> <string name="about_translate_cancel">Cancel</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
<string name="showcase_view_got_it_button">Got it!</string> <string name="showcase_view_got_it_button">Got it!</string>
<string name="showcase_view_whole_nearby_activity">These are the places near you that need pictures to illustrate their Wikipedia articles</string> <string name="showcase_view_whole_nearby_activity">These are the places near you that need pictures to illustrate their Wikipedia articles</string>
<string name="showcase_view_list_icon">Tapping this button brings up a list of these places</string> <string name="showcase_view_list_icon">Tapping this button brings up a list of these places</string>
<string name="showcase_view_plus_fab">You can upload a picture for any place from your gallery or camera</string> <string name="showcase_view_plus_fab">You can upload a picture for any place from your gallery or camera</string>
<string name="no_images_found">No images found!</string> <string name="no_images_found">No images found!</string>
<string name="error_loading_images">Error occurred while loading images.</string> <string name="error_loading_images">Error occurred while loading images.</string>
<string name="image_uploaded_by">Uploaded by: %1$s</string> <string name="image_uploaded_by">Uploaded by: %1$s</string>
<string name="block_notification">You are blocked from editing Commons</string> <string name="block_notification">You are blocked from editing Commons</string>
<string name="share_app_title">Share App</string> <string name="appwidget_img">Pic of the Day</string>
<string name="share_coordinates_not_present">Coordinates were not specified during image selection</string> <string name="app_widget_heading">Pic of the Day</string>
<string name="error_fetching_nearby_places">Error fetching nearby places.</string>
<string name="appwidget_img">Pic of the Day</string>
<string name="app_widget_heading">Pic of the Day</string>
<string name="menu_search_button">Search</string> <string name="menu_search_button">Search</string>
<string name="search_commons">Search Commons</string> <string name="search_commons">Search Commons</string>
<string name="images_not_found">No Images matching %1$s found</string> <string name="images_not_found">No Images matching %1$s found</string>
@ -325,6 +322,10 @@
<string name="correct">Correct Answer</string> <string name="correct">Correct Answer</string>
<string name="wrong">Wrong Answer</string> <string name="wrong">Wrong Answer</string>
<string name="quiz_screenshot_question">Is this screenshot OK to upload?</string> <string name="quiz_screenshot_question">Is this screenshot OK to upload?</string>
<string name="share_app_title">Share App</string>
<string name="share_coordinates_not_present">Coordinates were not specified during image selection</string>
<string name="error_fetching_nearby_places">Error fetching nearby places.</string>
<string name="add_description">+ Add description</string>
<string name="delete_recent_searches_dialog">Are you sure you want to clear your search history?</string> <string name="delete_recent_searches_dialog">Are you sure you want to clear your search history?</string>
<string name="search_history_deleted">Search history deleted</string> <string name="search_history_deleted">Search history deleted</string>