mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
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:
parent
e4c518ccce
commit
12a83da3a2
12 changed files with 622 additions and 122 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/src/main/java/fr/free/nrw/commons/upload/Language.java
Normal file
29
app/src/main/java/fr/free/nrw/commons/upload/Language.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
33
app/src/main/res/layout/row_item_description.xml
Normal file
33
app/src/main/res/layout/row_item_description.xml
Normal 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>
|
||||||
27
app/src/main/res/layout/row_item_languages_spinner.xml
Normal file
27
app/src/main/res/layout/row_item_languages_spinner.xml
Normal 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>
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue